Introducción

En un estudio de queso Cheddar realizado en el Valle de Latrobe (Victoria, Australia), se estudiaron muestras de queso en las que se analizó su composición química y fueron dadas a probar a distintos sujetos para que valoraran su sabor. Los valores asignados a cada queso son el resultado de combinar las distintas valoraciones.

El DataFrame cheddar de la librería faraway consiste de 30 muestras de queso Cheddar en las que se ha medido el sabor (taste) y las concentraciones de ácido acético (Acetic), ácido sulfhídrico (H2S) y lactosa (Lactic).

Tenenemos un conjunto de datos en el que se recogen observaciones de una cata de quesos, nuestras variables son:

· Taste: una valoración subjetiva de los jueces.

· Acetic: la concentración de ácido acético.

· H2S: la concentración de sulfito de hidrógeno.

· Lactic: concentración de ácido láctico.

Cargamos los datos y enseñamos las primeras observaciones.

Si en nuestro dataset tuviesemos entradas vacías (NA), tenemos varias posibilidades para lidiar con este problema:

Pero en nuestro caso evaluamos y no hay valores missing.

En nuestro caso, todas las variables son numéricas (cuantitativas). No hay ninguna variable categórica ni cualitativa. Si hubiese, tendríamos que transformarlas en variables binarias. Para ello, deberíamos hacer encoding a variables binarias, el lenguaje de programación R nos permite utilizar as.numeric.

Con estas variables vamos a intentar explicar cómo los valores observados de una variable Y (taste) dependen de los valores de otras variables (Acetic, H2S, Latcic), a través de una relación funcional lineal del tipo Y = f(X). También vamos a intentar predecir el valor de la variable Y para valores no observados de las variables X.

Tenemos 30 observaciones en nuestro dataset. Ahora procedemos a divirlo en el conjunto de train y test. El primero lo utilizaremos para entrenar nuestros modelos y el segundo lo usaremos para cuantificar el error de los modelos.

Para asegurar que sea reproducible utilizamos una semilla, que permite fijar los valores pseudoaleatorios obtenidos en muchas de las funciones utilizadas.

Hacemos un estudio preliminar de nuestras variables. Mostramos un scatter plot de cada variable contrastada con el resto. Esto permite ver a ojo si algún par de variables tiene correlación.

Ahora, utilizamos la función summary de R, la cual nos permite estimar algunos de las características de la distribución del dataset. La siguiente tabla nos muestra los estadísticos más comunes: el mínimo, máximo, mediana, media y el 1er y 3er cuartil.




Presentamos el modelo:

Hacemos las gráficas de dispersión entre la variable respuesta taste y las variables predictoras Acetic, H2S, Lactic.

Podemos observar que la que aperentemente guarda una menor relación lineal con taste es la variable Acetic, este hecho será reafirmado más adelante.

Estudio y evaluación del modelo completo.

Intentaremos predecir la variable taste usando el resto de variables. Para empezar, definimos el modelo completo, el cual se usan todas las variables para nuestro modelo lineal múltiple.

\[ Y_i =\beta_0 + \beta_1 x_{i1} + \dots + \beta_{p-1}x_{i(p-1)} + \epsilon_i,\quad i=1,\dots,n \] donde \(Y_i\) es el valor de la variable respuesta para el individuo \(i\)-ésimo, \(\beta_0\) y los \(\beta_j\) son los parámetros \(j = 1, ..., p - 1\), \(x_{ij}\) son los elementos de la matriz de las variables explicativas \(\epsilon_i\) es el término del error aleatorio que suponemos que se distribuye como una \(\mathcal{N}(0,\sigma^2)\), donde \(\sigma^2\) es la varianza que suele ser desconocida.

Resolución mediante matrices

Utilizamos el método de mínimos cuadrados que estima los valores \(\hat{\beta}\) intentando minimizar los errores \(\epsilon\). Como hemos visto en clase, la fórmula que se deduce es:

\[ \hat{\beta} = (X^tX)^{-1}X^tY \] donde \(X\) es una columna de 1’s concatenada con las variables que usamos para predecir.

Por tanto, aproximamos las \(\beta\) modelo lineal completo con los valores de \(\hat{\beta}_0,\dots,\hat{\beta}_3\) con los siguientes valores:

\[ \hat{\beta}_0=-28.8767696,\quad\hat{\beta}_1=0.3277413,\quad\hat{\beta}_2=3.911841,\quad\hat{\beta}_3=19.6705434 \]

Resolución usando librerias de R

Podemos utilizar la función \(lm\), ya programada en R. Definimos el modelo completo, y comprobamos las betas:

\[ taste \sim Acetic \, + \, H2S \, + \, Lactic, \, \, data = cheddar \]

Estudiemos preliminarmente si es un modelo lineal adecuado, para ello comprobaremos las hipótesis estándar del modelo lineal de regresión usando el test de normalidad Shapiro-Wilk. La función \(shapiro.test\) le pasamos por parámetro el residuo/error de cada una de las muestras y nos devuelve un \(p\)-valor.

Observamos que estamos en la hipótesis de que el error nuestro modelo se distribuye de manera normal, ya que el p-valor es \(0.8865 > 0.05\).

Otro aspecto que debemos saber es si la media de los errores será nula o no, para ello usamos una función implementada en R que nos afirma que en nuestro caso esto es así. Respecto a los errores tenemos que saber que se distribuyen con varianza constante, que de manera análoga comprobamos, teniendo p-valores lo suficientemente bajos como para rechazar varianza no constante. De igual manera tenemos que no hay autocorrelación en el modelo completo.

Una vez hemos concluido que aunque estamos en las hipótesis de regresión lineal el modelo completo a pesar de ser el más complejo probablemente da resultados similares a otro más simple.

Tras realizar el summary del modelo, una observación muy importante que sacamos es que el p-valor de Acetic es muy grande (0.94) por lo que no va a ser una variable significativa y por tanto con casi toda seguridad no tiene impacto real en el modelo.

Por el contrario el resto de variables sí son significativas por tener p-valor inferior a 0.5, destacando Lactic por tener un beta mayor que H2S, lo que ppuede hacernos llegar a pensar que cobre más importancia en un modelo final.

Correlaciones y tabla de resultados con el estudio de sus p-valores

Usamos el paquete \(GGplot\) de R, el cual nos permite visualizar la correlación y dispersión entre las distintas variables.

Pdemos apreciar que la variable con menor coefeciente de correlación de Pearson es Acetic,mientra que el resto de variables tienen un valor bastante mayor. Cabe destacar que todos tienen un signo positivo, lo que nos dice que en general al aumentar una aumenta la otra.

¿Tiene outliers nuestra muestra?

Para comprobarlo basta realizar el test de Bonferroni sobre nuestro modelo completo:

Concluimos con un nivel \(\alpha\) = 0.05 que no tenemos ningún outlier en nuestra. Lo más cercano a un outlier que tenemos es la observación número 15, que tiene un valor Bonferroni p de 0.17453 (no se acerca a 0.05). Por tanto, no tenemos razones por las que eliminar alguna observación inusual de nuestro conjunto de datos.

Esto se puede comprobar graficamente a través del siguiente gráfico, el cual mide la influencia de cada observación sobre cada una de las betas de nuestro modelo.

Vemos que la que más influye es la antes mencionada observación 15 y por tanto deberíamos considerar si es outlier. Hemos comprobado que sucedería al eliminar esa observación de la muestra, y si bien mejoraba algún p-valor de las hipótesis de regresión, en otros los empeoraba, así que hemos decidido no eliminarla y esperarnos a ver el caso en las seeds que estudiaremos con más detalles si sale de la muestra como observación influyente.

¿Cuál es el mejor modelo?

Como dice el Principio de la Navaja de Ockham, a menudo la explicación más simple es la correcta. Queremos seleccionar predictores que explican los datos de la manera más simple posible, sin disminuir la calidad de las predicciones mucho.

Separacion del dataset en conjuntos de entrenamiento y test (70-30%)

Hemos escogido distintas semillas para estar en condiciones de realizar un estudio más amplio, en la elección de las mismas se ha intentado evitar aquellas que generaban muestras demasiado similares. Las semillas usadas son 1, 1100 y 5 posteriormente se introducirán dos más para afinar en el cálculo de errores.

Consideremos los conjuntos de entrenamiento resultantes de las semillas: train.1(semilla 1), train.2(semilla 1100), train.3(semilla 5).Veaamos que modelos debemos considerar en base a nuestros train.

Método Backward

Partimos del modelo completo estudiado en la sección anterior, eso sí, evaluado en nuestros respectivos train y aplicamos con \(\alpha\) = 0.05, el método de Backward, que consiste en eliminar la variable que menos influya a la predicción. Primero realizamos una iteración explícita del método sobre la primera semilla, y posteriormente se construyen a través de la libreria mixlm de R.

Eliminamos Acetic del modelo debido que su p-valor es >0.05.

Repetimos el proceso con la variable H2S, ya que tiene un p-valor mayor que \(\alpha = 0.05\)

El p-valor es menor que \(\alpha = 0.05\), por lo que hemos concluido, ya que no tenemos suficiente certeza para poder eliminar otra variable.Por tanto, tenemos como resultado que la variable que mejor explica el taste es Lactic. Modelo resultante: taste ~ Lactic, data = cheddar[train.1,].

Por otro lado los modelos backward resultantes por mixlm son:

taste ~ H2S + Lactic, data = cheddar[train.2,] y por otro lado taste ~ H2S + Lactic, data = cheddar[train.3,].

Método Forward

El método Forward consiste en empezar con un modelo de una variable y vamos añadiendo las que más influyan, desarrollaremos el primer modelo de forma explícita y el resto los generaremos con mixlm. De esta manera tenemos:

Actualizamos añadiendo Lactic por tener el menor p-valor.

Con nivel de significación \(\alpha\) = 0.05 este sería nuestro modelo final. Modelo resultante = taste ~ Lactic, data = cheddar[train.1,]
Por otro lado los modelos forward resultantes por mixlm son:

taste ~ H2S + Lactic, data = cheddar[train.2,] y por otro lado taste ~ H2S + Lactic, data = cheddar[train.3,].

Construcción por criterios

En esta subsección trataremos de encontrar un candidato a mejor modelo, construyendo nuestros modelos usando distintos enfoques. Tras aplicar los siguientes criterios a la hora del desarrollo de modelos: \(R^2\) ajustado, Cp de Mallows, Criterio de Informacion de Bayes (BIC), Criterio de Informacion de Akaike (AIC) eligiendo el que nos de un menor o mayor coeficiente según el método (los desarrolos se pueden encontrar en el script), llegamos a las siguientes conclusiones:
solo aparece un modelo nuevo usando el criterio del estadístico \(R^2\) para la primera semilla, taste ~ H2S + Lactic, data = cheddar[train.1,].
Notamos que la combinación de H2S + L aparece en todos nuestros conjuntos de entrenamiento en algún momento, es candidata a ser nuestra mejor elección.

Comparamos los modelos obtenidos hasta ahora en su respectiva muestra de entrenamiento con el modelo completo en ese conjunto de entrenamiento.

Analysis of Variance Table

Model 1: taste ~ Lactic
Model 2: taste ~ Acetic + H2S + Lactic
  Res.Df    RSS Df Sum of Sq      F  Pr(>F)  
1     19 1853.5                              
2     17 1410.7  2    442.84 2.6683 0.09821 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Con estos p-valores podemos decir que con un nivel de significación \(\alpha\) ningún modelo es notablemente diferente de su contraparte salvo en el caso de los modelos resultantes en train2 esto puede ser por la cantidad de observaciones influyentes presentes en la muestra, lo trataremos en la siguiente sección.

Diagnostico: Comprobaciones de hipotesis, outliers y observaciones influyentes

En esta sección estudiaremos si nuestros modelos cumplen las condiciones necesarias de un modelo de regresión lineal.

Nuestro enfoque consistirá en un análisis gráfico, acompañado de tests estadísticos en los casos en los que se aprecie una discrepancia notable.

¿Son nuestros modelos, modelos de regresión lineal?: Comprobación de hipótesis.

En la sección 3 se toma un enfoque naïve a la hora de construir los modelos, ya que no hemos estudiado si hay observaciones influyentes, podríamos tener una muestra que no es la adecuada para el estudio de nuestros datos.

Un modelo de regresión lineal debe satisfacer las siguientes hipótesis con nivel de significación \(\alpha\) adecuado:

  1. Los errores \(\epsilon_{i}\) tienen distribución normal.
  2. Los errores \(\epsilon_{i}\) tienen media cero.
  3. Los errores \(\epsilon_{i}\) tienen varianza constante.
  4. Los errores \(\epsilon_{i}\) no están correlacionados.

Podemos observar que se verifican a nivel de significación \(\alpha\) = 0.05 se verifican todas las hipótesis de modelo de regresión lineal. En las siguientes gráficas podemos observar como los residuos de los modelos taste ~ H2S + L de los conjuntos train2 y train3 se comportan mejor que cualquiera de los modelos propuestos en la muestra train1

Posteriormente, realizamos un estudio de la colinealidad. Para ello, observamos que el modelo taste ~ Lactic , data=cheddar[train.1,] solo tiene un predictor luego no hay presente ningún tipo colinealidad.

Nuestros valores son muy buenos, entendiendo por bueno VIF < 10, por lo tanto no tenenemos que preocuparnos de una colinealidad grave entre las variables.

Estudio de outliers

A fin de obtener distintos puntos de vista utilizaremos dos métodos, un valor de Bonferroni en un estadístico \(t_{1-\frac{\alpha}{2n};n-p-1}\) y la función outlierTest que utiliza p-valores de Bonferroni obtenidos a través de t-tests.

En los cuatro modelos y bajo los dos criterios no se obtiene ninguna observación que se pueda aceptar como outlier a nivel de significación \(\alpha\) = 0.05

Estudio de observaciones Influyentes

Al igual que en la anterior sección a fin de poder encontrar el criterio que mejor se ajuste a nuestro modelo, en el que hay que tener en cuenta que es una muestra de tamaño reducido, utilizaremos varios criterios, además de distintas técnicas gráficas. Los criterios usados serán:
1.Criterio 1: valores leverage (hii) mayores que \(\frac{2p}{n}\).
2.Criterio 2: valores |DFFITS| son mayores que \(2 \cdot \sqrt{\frac{2p}{n}}\).

3.Criterio 3: valores |DFBETAS| mayores que \(2 \cdot \sqrt{\frac{2p}{n}}\).

4.Criterio 4: InfluencePlot.

En la siguiente tabla observamos las observaciones influyentes obtenidas por cada criterio.

Tomamos la decisión de elegir los elementos que se repitan en varios ya que si eliminásemos los del criterio 3 el resultado sería demasiado pequeño para ser apto para la regresión lineal. Nuestro criterio a seguir es que estén en al menos dos criterios de los restantes.

Estas observaciones son las presentes en la cuarta columna de la tabla y en general son en las primeras en las que nos fijemos a la hora de ver si las tomamos como influyentes o no.

Bajo nuestro criterio quedarían como posibles influyentes las siguientes observaciones:

Ahora es cuando tenemos que determinar si van a ser influyentes o no, esto lo veremos comparando los modelos con las muestras de entrenamiento sin eliminar influyentes y con las muestras modificadas, y evaluar si mejoran o empeoran los p-valores de las hipótesis de los modelos de regresión.

taste ~ + Lactic, data = cheddar[train.1,] vs taste ~ Lactic, data = cheddar[train.1inf,]

Nuestras hipótesis del modelo lineal se ven notablemente mejoradas, tenemos una distribución más parecida a una normal, mejor distribuida en torno a una lineal.
Realizamos un pequeño intercambio en el que nuestra varianza parece menos constante pero se mantiene por encima de todos los niveles de significación habituales.
Tomamos la decisión de actualizar cheddar[train.1,] con cheddar[traininf.1,], que es la versión sin observaciones influyentes. ### taste ~ H2S + Lactic, data = cheddar[train.1,] vs taste ~ H2S + Lactic, data = cheddar[train.1critinf,]

Este es un caso un tanto particular, tenemos unos datos perfectamente distribuidos, pero ya lo estaban antes practicamente. A cambio de eso perdemos un cierto grado de linealidad que hay que tener en cuenta, en este caso no hay una diferencia tan notable con el modelo como en que solo incorporaba a Lactic.

Tomamos la decisión de actualizar cheddar[train.1crit,] con cheddar[train.1critinf,], que es la versión sin observaciones influyentes.

taste ~ H2S + Lactic, data = cheddar[train.2,] vs taste ~ H2S + Lactic, data = cheddar[train.2inf,]

En cierta manera es notable que al eliminar nuestras influyentes y en un dataset tan pequeño no genere a penas diferencia, en todo caso nos mejora todas las hipótesis del modelo lineal, se puede afirmar que es un modelo mejor para trabajar sobre el a priori.

Tomamos la decisión de actualizar cheddar[train.2,] con cheddar[traininf.2,], que es la versión sin observaciones influyentes.

taste ~ H2S + Lactic, data = cheddar[train.3,]

En este modelo, bajo el criterio de elección de observaciones influyentes que elegimos para tratar nuestros datos, este modelo no presentaba ninguna observación influyente, por lo que se mantiene como está.

Errores de Test. Comparacion de Modelos

Nuestro razonamiento para enfrentarnos a esta sección es el siguiente, nos han salido dos modelos posibles y para comprender cual se ajusta mejor a nuestros datos vamos a escoger cinco seeds y evaluar cada modelo en todas ellas, a fin de hacer una media de los errores.

Para esto usamos las tres seeds que hemos utilizado a lo largo del documento, y le añadimos otras dos elegidas al azar. Nótese que evaluar en la primera seed ya está hecho, pues en esta nos salían los dos modelos a considerar. Además en las seeds dos y tres ya está hecho para el modelo con H2S + Lactic, pero hay que repetir el proceso para el otro modelo. De esta manera realizamos los mismos cálculos que los realizados en la parte de diagnóstico, sobre las combinaciones. Esto es, nos aseguramos que cada modelo con todos los train cumpla las hipótesis de normalidad, media de errores nula, homocedasticidad, linealidad y autocorrelación. Después de esto nos planteamos si tiene datos influyentes según las funciones adecuadas, en caso de tenerlos realizamos una prueba. los quitamos del train y vemos si se mejora el p-valor de alguna de las características anteriores y en base a eso decidimos si eliminamos las observaciones influyentes o no.

Con todo eso realizado llegamos a la siguiente tabla, que nos permite asumir como validos todos los casos y calcular sus errores.

Calculamos los errores de cada método como la media de los errores del método aplicado en cada seed. De esta manera, el error medio obtenido es:

Como el error del modelo H2S + Lactic es menor, ese es el modelo que llamaremos final y que se ajustará lo mejor posible a los datos de nuestro fichero.

Conclusión: presentación del modelo final

Finalmente por comparación de los errores sabemos que el modelo final que presentamos es: taste ~ H2S + Lactic , que tiene sentido ya que Acetic no era significativa. otro hecho que lo reafirma es que en la construcción de modelos salieron en todos los casos este modelo, salvo en el método backward y en el método forward de la primera semilla.

Presentamos el summary de nuestro modelo, del que sacaremos más informción en un futuro.

A su vez enseñamos los graficos de este modelo:

Ahora vamos a asegurarnos que verifica las hipótesis para una regresión lineal y además de revisar con outlierTest que no tenemos outliers. También planteamos una hipótesis sobre la nulidad de la media de los errores y vemos que su varianza es constante además de calcularla.

Dicho esto procedemos a la presentación del modelo con sus betas asociados, que si bien se pueden recoger del summary, también los calculamos de forma matricial igual que se hizo con el modelo completo en su momento.

El resultado sería taste ~ -27.591815 +3.9946267 H2S +19.887204 Lactic Nótese que sigue siendo acorde al modelo completo donde el \(\beta\) de Lactic es muy superior en comparación al de H2S.

Presentamos ahora \(R^{2}\) y \(R^{2}_{adj}\), estas como antes se pueden recoger directamente del summary, también las calculamos a partir de los errores y la tabla anova, dando el resultado de 0.6517024 y 0.6259025 respectivamente. Además presentamos el vector de p-valores.

Observamos que todos los p-valores están por debajo de nuestra alpha de referencia.

También presentamos intervalos para las betas de Bonferroni y Scheffé:

Finalmente buscamos una representación de la regresión que tenemos en 3 dimensiones ya que el modelo final consta de una variable respuesta y dos predictoras y vemos el plano de regresión, marcando en rojo las observaciones que peor se ajustan.

Anexo

install.packages("faraway")
install.packages("leaps")
install.packages("MASS")
install.packages("PASWR")
install.packages("car")
install.packages("ggplot2")
install.packages("GGally")
install.packages("corrplot")
install.packages("scatterplot3d")
install.packages("lmtest")
install.packages("plotly")
install.packages("mixlm")


library(faraway)
library(leaps)
library(MASS)
library(PASWR)
library(car)
library(ggplot2)
library(GGally)
library(corrplot)
library(plotly)
library(scatterplot3d)
library(lmtest)
library(mixlm)





# 1) Introduccion

data(cheddar)
attach(cheddar)

# Variable Respuesta: taste
# Variables Predictoras: Acetic, H2S, Lactic


# Estudiamos el tipo de las variables que van a formar parte de los posibles modelos
sapply(cheddar, class) # todas las variables son numericas
head(cheddar)

# Comprobamos que no hay entradas vacias
any(is.na(cheddar))

# De haberlas habido, podriamos haber tomado las siguientes decisiones:
#  - eliminar las observaciones con valores NA
#  - eliminar variables si muchas de las entradas vacias aparecen en ella
#  - emplear métodos para predecir que valores deberian apercer en dichas entradas



# Histogramas de todas las variables
ids <- names(cheddar)
layout(matrix(1:4, nrow = 1))
y_lab_string <- "Cantidad"
for (id in ids) {
  hist(cheddar[, id], xlab = id, ylab = y_lab_string, main = paste("Histogram of ", id))
  y_lab_string <- ""
}


# Graficas de las relaciones entre variables.
plot(cheddar)

# Graficas de dispersion entre la variable respuesta "taste" y las variables predictoras.
layout(matrix(1:3, nrow = 1))

plot(Acetic, taste,
     main = "Relación entre Taste y Acetic",
     xlab = "Acetic", ylab = "Taste",
     pch = 19, frame = FALSE)


plot(H2S, taste,
     main = "Relación entre Taste y H2S",
     xlab = "H2S", ylab = "Taste",
     pch = 19, frame = FALSE)


plot(Lactic, taste,
     main = "Relación entre Taste y Lactic",
     xlab = "Lactic", ylab = "Taste",
     pch = 19, frame = FALSE)


layout(matrix(1:1, nrow = 1))
summary(cheddar)





# 2) Estudio y evaluacion del modelo completo

x <- model.matrix( ~ Acetic + H2S + Lactic, data = cheddar)
betahat <- solve(crossprod(x, x), crossprod(x, taste))
betahat <- c(betahat)
betahat

# Comprobamos el resultado con funciones ya implementadas
model.all <- lm(taste ~ ., data = cheddar)
summary(model.all)
model.all$coefficients

anova(model.all)



# Intervalos de confianza de las betas del modelo completo
confint(model.all)

# Observamos que 0 esta en el intervalo de confianza de beta_0 y beta_Acetic, planteamos dos tests
#    con hipótesis nula beta_i = 0 y hipotesis alternativa beta_i != 0.

# Comenzamos con beta_Acetic pues el valor estimado es más cercano a 0 que el de beta_0
modnoAcetic <- lm(taste ~ H2S + Lactic, data=cheddar)
anova(modnoAcetic,model.all) # no solo el p-valor > 0.05 sino que de hecho p-valor ~ 1, aceptamos la hipotesis nula.

modnoInterceptor <- lm(taste ~ H2S + Lactic + 0, data=cheddar) # modelo reducido sin interceptor
anova(modnoInterceptor,model.all) # el p-valor es menor que 0.05, luego no es suficiente para rechazar la hipotesis nula


# Veamos los p-valores de las variables predictoras
summary(model.all)$coeff[,4]
# Observamso que el p-valor de Acetic es el mas elevado, este resultado junto con el contrate de hipotesis que hemos hecho
#  podemos deducir que la variable Acetic no sera muy relevante para el estudio de los distintos modelos que estudiaremos.


# Correlaciones de las variables que intervienen en el modelo completo
cor(cheddar)
ggpairs(cheddar)

mat_cor <- cor(cheddar, method = "pearson")
corrplot(mat_cor, type = "upper", order = "hclust", tl.col = "black", tl.srt = 45)


# Por ultimo veamos si hay outliers en el modelo completo
Model.all<-fortify(model.all)
outlierTest(model.all) # no los hay

# Por el metodo de Bonferroni
alpha <- 0.05
BCV <- qt(1-alpha/(2*30),26) # el valor critico de Bonferroni t_{1-alpha/2n;n-p-1}, n=30,p=3
BCV
sum(abs(rstudent(model.all))>BCV) # el metodo no nos da ninguna observacion

sort(abs(rstandard(model.all)),decreasing = TRUE)[1:3] # estos valores estan relativamente lejanos de BCV


# Veamos si por influenceIndexPlot() hay alguna observacion que pueda ser relevante
influenceIndexPlot(model.all) # en la tercera grafica se ve que la observacion 15 tiene un comportamiento anormal

# Comprobemos si los supuestos de los modelos de regresion lineal mejoran al retirar esta observacion
#  de nuestro dataset. De ser asi, aceptamos que pueda ser una observacion que pejudique a nuestro modelo.
model.all_15<- lm(taste ~ ., data = cheddar[-15,])

# Homocedasticidad
ncvTest(model.all)
ncvTest(model.all_15) # empeora

# Normalidad
shapiro.test(resid(model.all))
shapiro.test(resid(model.all_15))# mejora

# Autocorrelacion
durbinWatsonTest(model.all)
durbinWatsonTest(model.all_15)# mejora

# Linealidad
resettest(model.all, power=2:3, type="regressor", data=cheddar)
resettest(model.all_15, power=2:3, type="regressor", data=cheddar)# empeora

# En el computo global no parece que los p-valores de estos tests den a entender una mejoria general del modelo.
#  Si bien es cierto, tampoco los empeora y dependiendo del criterio a seguir podriamos decidir si es relevante o no.
#  Nosotros hemos decidido no considerar la observacion 15 como tal.





# 3) Seleccion del mejor modelo. Metodos por pasos y por criterios

# Separacion del dataset en conjuntos de entrenamiento y test (70-30%)

# Hemos considerado varias semillas para abarcar más modelos. Además, hemos intentado evitar
#  en la medida de lo poible que se repitan muchos elementos en los distintos conjuntos de test seleccionados.

set.seed(1)
train.1 <- sample(c(TRUE, FALSE), size = nrow(cheddar), replace = TRUE, prob = c(0.7, 0.3))
test.1 <- (!train.1)
sum(test.1)
model.all1 <- lm(taste ~ ., data = cheddar[train.1,])

set.seed(1100)
train.2 <- sample(c(TRUE, FALSE), size = nrow(cheddar), replace = TRUE, prob = c(0.7, 0.3))
test.2 <- (!train.2)
sum(test.2)
sum(test.1==TRUE & test.2==TRUE)#solo 1 preseguimos
model.all2 <- lm(taste ~ ., data = cheddar[train.2,])

set.seed(5)
train.3 <- sample(c(TRUE, FALSE), size = nrow(cheddar), replace = TRUE, prob = c(0.7, 0.3))
test.3 <- (!train.3)
sum(test.3)
sum(test.1==TRUE & test.3==TRUE)
sum(test.2==TRUE & test.3==TRUE)
model.all3 <- lm(taste ~ ., data = cheddar[train.3,])



# i) BACKWARD (alpha=0.05)

drop1(model.all1, test = "F")
# quitamos Acetic del modelo por ser la de mayor p-valor

model.updateB1 <- update(model.all1, . ~ . - Acetic)
drop1(model.updateB1, test = "F")
# quitamos H2S del modelo por ser la de mayor p-valor

model.updateB2 <- update(model.updateB1, . ~ . - H2S)
drop1(model.updateB2, test = "F")
# termina el proceso pues el p-valor de Lactic no llega a alpha

model.1 <- lm(taste ~ Lactic, data = cheddar[train.1,])
summary(model.1)

# Para evitar repetir este proceso usamos el package mixlm con el que obtenemos los mismos resultados.
model.1 <- mixlm::backward(model.all1, alpha=0.05)
summary(model.1) # LACTIC

model.2 <- mixlm::backward(model.all2, alpha=0.05)
summary(model.2) # H2S + LACTIC

model.3 <- mixlm::backward(model.all3, alpha=0.05)
summary(model.3) # H2S + LACTIC



# ii) FORWARD (alpha=0.05)
SCOPE <- (~ . + Acetic + H2S + Lactic)
model.inicial <- lm(taste ~ 1, data = cheddar[train.1,]) # solo con termino independiente

add1(model.inicial, scope = SCOPE, test = "F")
# Añadimos Lactic por ser la variable predictora con menor p-valor
model.updateF1 <- update(model.inicial, . ~ . + Lactic)

add1(model.updateF1, scope = SCOPE, test = "F")
# No añadimos ninguna variable pues todos los p-valores superan la barrera de alpha

model.1a <- lm(taste ~ Lactic, data = cheddar[train.1,])
summary(model.1a)


# Al igual que en BACKWARD usamos el paquete mixlm para automatizar el proceso de FORWARD.
model.1a <- mixlm::forward(model.all1, alpha=0.05)
summary(model.1a) # LACTIC

model.2a <- mixlm::forward(model.all2, alpha=0.05)
summary(model.2a) # H2S + LACTIC

model.3a <- mixlm::forward(model.all3, alpha=0.05)
summary(model.3a) # H2S + LACTIC

# Nótese que los modelos obtenidos por BACKWARD y FORWARD coinciden para cada conjunto train.



# iii) CRITERIOS

# R2 ajustado
models1 <- regsubsets(taste ~ ., data = cheddar[train.1,])
models2 <- regsubsets(taste ~ ., data = cheddar[train.2,])
models3 <- regsubsets(taste ~ ., data = cheddar[train.3,])

summary(models1)
summary(models2)
summary(models3)

MR2adj1 <- summary(models1)$adjr2
MR2adj2 <- summary(models2)$adjr2
MR2adj3 <- summary(models3)$adjr2

summary(models1)$which[which.max(MR2adj1), ]
summary(models2)$which[which.max(MR2adj2), ]
summary(models3)$which[which.max(MR2adj3), ]



# Cp de Mallows
MCp1 <- summary(models1)$cp
MCp2 <- summary(models2)$cp
MCp3 <- summary(models3)$cp


summary(models1)$which[which.min(MCp1), ]
summary(models2)$which[which.min(MCp2), ]
summary(models3)$which[which.min(MCp3), ]


# Criterio de Informacion de Bayes (BIC)
MBIC1 <- summary(models1)$bic
MBIC2 <- summary(models2)$bic
MBIC3 <- summary(models3)$bic

summary(models1)$which[which.min(MBIC1), ]
summary(models2)$which[which.min(MBIC2), ]
summary(models3)$which[which.min(MBIC3), ]

# Criterio de Informacion de Akaike (AIC)
stepAIC(model.all1, scope = SCOPE, k = 2)
stepAIC(model.all2, scope = SCOPE, k = 2)
stepAIC(model.all3, scope = SCOPE, k = 2)


# Para el conjunto train.1 aparecen modelos con Lactic y H2S + Lactic como variables predictoras,
#  mientras que para los conjuntos train.2 y train.3 unicamente aparece el modelo taste ~ H2S + Lactic.
model.1crit <- lm(taste ~ H2S + Lactic, data=cheddar[train.1,])

# Esto nos puede llevar a pensar que el modelo final vaya a ser el que utiliza H2S y Lactic.

model.1
model.1crit
model.2
model.3

anova(model.1,model.all1)
anova(model.1crit,model.all1)
anova(model.2,model.all2)
anova(model.3,model.all3)
# De esta forma vemos que los modelos creados son mejores que los completos.





# 4) Diagnostico. Comprobaciones de hipotesis, outliers y observaciones influyentes

# Comprobacion de hipotesis de los  modelos

# Linealidad

resettest(model.1, power=2:3, type="regressor", data=cheddar[train.1,])
resettest(model.1crit, power=2:3, type="regressor", data=cheddar[train.1,])
resettest(model.2, power=2:3, type="regressor", data=cheddar[train.2,])
resettest(model.3, power=2:3, type="regressor", data=cheddar[train.3,])
# p-valores > 0.05 luego aceptamos hipótesis de linealidad en todos los casos

plot(cheddar$H2S, cheddar$taste,
     main = "Relacion entre Taste y H2S",
     xlab = "H2S", ylab = "Taste",
     pch = 19, frame = FALSE)
plot(cheddar$Lactic, cheddar$taste,
     main = "Relacion entre Taste y Lactic",
     xlab = "Lactic", ylab = "Taste",
     pch = 19, frame = FALSE)



# Normalidad y Autocorrelacion

shapiro.test(resid(model.1)) # p-valor > 0.05 no se rechaza la hipótesis nula, i.e. la normalidad
qqnorm(resid(model.1))
qqline(resid(model.1))

shapiro.test(resid(model.1crit))#bien
qqnorm(resid(model.1crit))
qqline(resid(model.1crit))

shapiro.test(resid(model.2))#bien
qqnorm(resid(model.2))
qqline(resid(model.2))

shapiro.test(resid(model.3))#bien
qqnorm(resid(model.3))
qqline(resid(model.3))

# Observamos que las colas no siguen el mismo patrón que el resto de datos, lo que podría indicar que
#  el modelo no sigue una distribución normal. Sin embargo, al no afectar a un gran porcentaje de los datos y
#  teniendo en cuenta el resultado previo obtenido por el Test de Shapiro-Wilk no rechazamos la hipótesis de normalidad.


# Media de errores nula

t.test(resid(model.1), mu = 0, alternative = "two.sided")
t.test(resid(model.1crit), mu = 0, alternative = "two.sided")
t.test(resid(model.2), mu = 0, alternative = "two.sided")
t.test(resid(model.3), mu = 0, alternative = "two.sided")
# p-valores ~ 1 > 0.05 luego aceptamos la hipotesis nula en todos los casos



# Autocorrelacion

durbinWatsonTest(model.1)
durbinWatsonTest(model.1crit)
durbinWatsonTest(model.2)
durbinWatsonTest(model.3)
# p-valores > 0.05 luego rechazamos que haya autocorrelacion



# Homocedasticidad

fmodel1 <- fortify(model.1)
fmodel1crit <- fortify(model.1crit)
fmodel2 <- fortify(model.2)
fmodel3 <- fortify(model.3)

X1 <- fmodel1$.fitted
Y1 <- fmodel1$.stdresid

X1crit <- fmodel1crit$.fitted
Y1crit <- fmodel1crit$.stdresid

X2 <- fmodel2$.fitted
Y2 <- fmodel2$.stdresid

X3 <- fmodel3$.fitted
Y3 <- fmodel3$.stdresid

plot(X1, Y1, ylab = "Residuos estandarizados", xlab = "valores ajustados")
plot(X1crit, Y1crit, ylab = "Residuos estandarizados", xlab = "valores ajustados")
plot(X2, Y2, ylab = "Residuos estandarizados", xlab = "valores ajustados")#casi casi hay patron
plot(X3, Y3, ylab = "Residuos estandarizados", xlab = "valores ajustados")
# Los residuos se distribuyen de forma homogénea a lo largo de una banda horizontal, luego se verifica la hipótesis nula


ncvTest(model.1)
ncvTest(model.1crit)
ncvTest(model.2)
ncvTest(model.3)
# p-valores > 0.05, luego no hay evidencia para rechazar que la varianza sea constante



# Outliers

alpha <- 0.05
n1 <- nrow(cheddar[train.1,])
p1 <- nrow(summary(model.1)$coef)

n1crit <- nrow(cheddar[train.1,])
p1crit <- nrow(summary(model.1crit)$coef)

n2 <- nrow(cheddar[train.2,])
p2 <- nrow(summary(model.2)$coef)

n3 <- nrow(cheddar[train.3,])
p3 <- nrow(summary(model.3)$coef)


# El valor critico de Bonferroni t_{1-alpha/2n;n-p-1}
BCV1 <- qt(1 - alpha / (2 * n1), n1-p1-1)
BCV1crit <- qt(1 - alpha / (2 * n1crit), n1crit-p1crit-1)
BCV2 <- qt(1 - alpha / (2 * n2), n2-p2-1)
BCV3 <- qt(1 - alpha / (2 * n3), n3-p3-1)

sum(abs(rstudent(model.1)) > BCV1)
sum(abs(rstudent(model.1crit)) > BCV1crit)
sum(abs(rstudent(model.2)) > BCV2)
sum(abs(rstudent(model.3)) > BCV3)

outlierTest(model.1)#NA?
outlierTest(model.1crit) #NA?
outlierTest(model.2)
outlierTest(model.3)
# No hay outliers en ninguno de los dos modelos planteados



# Observaciones Influyentes

# Criterio 1: valores leverage (hii) mayores que 2p/n

X1 <- model.matrix(~ H2S+Lactic, data = cheddar[train.1,])
X1crit <- model.matrix(~ H2S+Lactic, data = cheddar[train.1,])
X2 <- model.matrix(~ H2S+Lactic, data = cheddar[train.2,])
X3 <- model.matrix(~ Lactic, data = cheddar[train.3,])

H1 <- X1 %*% solve(t(X1) %*% X1) %*% t(X1)
H1crit <- X1crit %*% solve(t(X1crit) %*% X1crit) %*% t(X1crit)
H2 <- X2 %*% solve(t(X2) %*% X2) %*% t(X2)
H3 <- X3 %*% solve(t(X3) %*% X3) %*% t(X3)

hii1 <- diag(H1)
hii1crit <- diag(H1crit)
hii2 <- diag(H2)
hii3 <- diag(H3)

hCV1 <- 2 * p1 / n1
hCV1crit <- 2 * p1crit / n1crit
hCV2 <- 2 * p2 / n2
hCV3 <- 2 * p3 / n3

sum(hii1 > hCV1)
which(hii1>hCV1)#1  5 16 23 24 26

sum(hii1crit > hCV1crit)
which(hii1crit>hCV1crit)

sum(hii2 > hCV2)
which(hii2>hCV2)

sum(hii3 > hCV3)


# Criterio 2: valores |DFFITS| son mayores que 2*sqrt(p/n)

dffitsCV1 <- 2 * sqrt(p1 / n1)
dffitsCV1crit <- 2 * sqrt(p1crit / n1crit)
dffitsCV2 <- 2 * sqrt(p2 / n2)
dffitsCV3 <- 2 * sqrt(p3 / n3)

dffitsmodel1 <- dffits(model.1)
dffitsmodel1crit <- dffits(model.1crit)
dffitsmodel2 <- dffits(model.2)
dffitsmodel3 <- dffits(model.3)

sum(dffitsmodel1 > dffitsCV1)
which(dffitsmodel1 > dffitsCV1)#1 12 24

sum(dffitsmodel1crit > dffitsCV1crit)
which(dffitsmodel1crit > dffitsCV1crit)#1, 12

sum(dffitsmodel2 > dffitsCV2)
sum(dffitsmodel3 > dffitsCV3)



# Criterio 3: valores |DFBETAS| mayores que 2/sqrt(n)

dfbetaCV1 <- 2 / sqrt(n1)
dfbetaCV1crit <- 2 / sqrt(n1crit)
dfbetaCV2 <- 2 / sqrt(n2)
dfbetaCV3 <- 2 / sqrt(n3)

dfbetamodel1 <- dfbeta(model.1)
dfbetamodel1crit <- dfbeta(model.1crit)
dfbetamodel2 <- dfbeta(model.2)
dfbetamodel3 <- dfbeta(model.3)


sum(dfbetamodel1[, 1] > dfbetaCV1)
sum(dfbetamodel1[, 2] > dfbetaCV1)
which(dfbetamodel1[, 1] > dfbetaCV1)
which(dfbetamodel1[, 2] > dfbetaCV1)

sum(dfbetamodel1crit[, 1] > dfbetaCV1crit)
sum(dfbetamodel1crit[, 2] > dfbetaCV1crit)
sum(dfbetamodel1crit[, 3] > dfbetaCV1crit)
which(dfbetamodel1crit[, 1] > dfbetaCV1crit)
which(dfbetamodel1crit[, 3] > dfbetaCV1crit)

sum(dfbetamodel2[, 1] > dfbetaCV2)
sum(dfbetamodel2[, 2] > dfbetaCV2)
sum(dfbetamodel2[, 3] > dfbetaCV2)
which(dfbetamodel2[, 1] > dfbetaCV2)
which(dfbetamodel2[, 3] > dfbetaCV2)

sum(dfbetamodel3[, 1] > dfbetaCV3)
sum(dfbetamodel3[, 2] > dfbetaCV3)
sum(dfbetamodel3[, 3] > dfbetaCV3)
which(dfbetamodel3[, 1] > dfbetaCV3)
which(dfbetamodel3[, 3] > dfbetaCV3)

# Dado que nuestro datset es pequeño, no tendremso en cuenta este metodo por dar demasiadas observaciones.


# Grafica con las distancias de Cook
influencePlot(model.1)
pos_influyentes_1 <- c(1,12,24)

influencePlot(model.1crit)
pos_influyentes_1crit <- c(1,8,12,23)

influencePlot(model.2)
pos_influyentes_2 <- c(1,6,7,8,15)

influencePlot(model.3)
pos_influyentes_3 <- c(1,7,15,19,24)



# Colinealidad
vif(model.1) # tiene sentido pues en model.1 solo hay una variable predictora
vif(model.1crit)
vif(model.2)
vif(model.3) # como los valores de VIF no son grando, no indican colinealidad grave


# Vamos a tomar como posibles influyentes las que aparecen por varios metodos en cada modelo

# En el 1: 1 12
pos_1 <- c(TRUE,rep(FALSE,10),TRUE,rep(FALSE,18))
train.1inf <- train.1&!pos_1
model.1inf <- lm(taste ~ Lactic, data = cheddar[train.1inf,])

ncvTest(model.1)
ncvTest(model.1inf) # empeora pero sigue cumpliendo la hipotesis

shapiro.test(resid(model.1))
shapiro.test(resid(model.1inf)) # mejora poco

durbinWatsonTest(model.1)
durbinWatsonTest(model.1inf) # mejora

resettest(model.1, power=2:3, type="regressor", data=cheddar[train.1inf,])
resettest(model.1inf, power=2:3, type="regressor", data=cheddar[train.1inf,]) # mejora bastante

# Redefinimos el modelo eliminando las observaciones influyentes de pos_1.
train.1aux<-train.1
train.1 <- train.1inf
model.1 <- model.1inf


# En el 1crit: 1 12  23
pos_1crit <- c(TRUE,rep(FALSE,10),TRUE,rep(FALSE,10),TRUE,rep(FALSE,7))
train.1critinf <- train.1&!pos_1crit
model.1critinf <- lm(taste ~H2S+Lactic , data = cheddar[train.1critinf,])

ncvTest(model.1crit)
ncvTest(model.1critinf) # empeora

shapiro.test(resid(model.1crit))
shapiro.test(resid(model.1critinf)) # mejora

durbinWatsonTest(model.1crit)
durbinWatsonTest(model.1critinf) # mejora bastante

resettest(model.1crit, power=2:3, type="regressor", data=cheddar[train.1,])
resettest(model.1critinf, power=2:3, type="regressor", data=cheddar[train.1critinf,]) # empeora dentro de aceptable

# Redefinimos el modelo eliminando las observaciones influyentes de pos_1crit.
train.1crit <- train.1critinf
model.1crit <- model.1critinf


# En el 2: 6
pos_2 <- c(rep(FALSE,5),TRUE,rep(FALSE,24))
train.2inf <- train.2&!pos_2
model.2inf <- lm(taste ~ H2S+Lactic, data = cheddar[train.2inf,])

ncvTest(model.2)
ncvTest(model.2inf) # mejora poco

shapiro.test(resid(model.2))
shapiro.test(resid(model.2inf)) # aproximadamente lo mismo

durbinWatsonTest(model.2)
durbinWatsonTest(model.2inf) # mejora

resettest(model.2, power=2:3, type="regressor", data=cheddar[train.2inf,])
resettest(model.2inf, power=2:3, type="regressor", data=cheddar[train.2inf,]) # aproximadamente lo mismo

# Redefinimos el modelo eliminando las observaciones influyentes de pos_2.
train.2 <- train.2inf
model.2 <- model.2inf


# En el modelo 3 no hacemos comprobaciones nada ya que no se repiten observaciones por distintos metodos.





# 5) Errores de Test. Comparacion de Modelos

# Vamos a considerar otras dos semillas para evaluar los modelos y elegir el mejor.
# Las tomamos de forma que no coincidan en la medida de lo posible los tests de las distintas particiones.
# Dividimos el conjunto total para las dos semillas nuevas.

set.seed((2234))
train.4 <- sample(c(TRUE, FALSE), size = nrow(cheddar), replace = TRUE, prob = c(0.7, 0.3))
test.4 <- (!train.4)
sum(test.4)
sum(test.1==TRUE & test.4==TRUE)
sum(test.2==TRUE & test.4==TRUE)
sum(test.3==TRUE & test.4==TRUE)


set.seed((131))
train.5 <- sample(c(TRUE, FALSE), size = nrow(cheddar), replace = TRUE, prob = c(0.7, 0.3))
test.5 <- (!train.5)
sum(test.5)
sum(test.1==TRUE & test.5==TRUE)
sum(test.2==TRUE & test.5==TRUE)
sum(test.3==TRUE & test.5==TRUE)
sum(test.4==TRUE & test.5==TRUE)

train.1h <- train.1crit
train.2h <- train.2
train.3h <- train.3
train.4h <- train.4
train.5h <- train.5

# Recalculamos train.2 porque fue modificado
set.seed(1100)
train.2 <- sample(c(TRUE, FALSE), size = nrow(cheddar), replace = TRUE, prob = c(0.7, 0.3))




# Veamso si podemos eliminar posibles influyentes en los modelos restantes

mh1 <- lm(taste ~ H2S + Lactic, data = cheddar[train.1h,]) # comprobados supuestos
mh2 <- lm(taste ~ H2S + Lactic, data = cheddar[train.2h,]) # comprobados supuestos
mh3 <- lm(taste ~ H2S + Lactic, data = cheddar[train.3h,]) # comprobados supuestos
mh4 <- lm(taste ~ H2S + Lactic, data = cheddar[train.4h,])
mh5 <- lm(taste ~ H2S + Lactic, data = cheddar[train.5h,])

m1 <- lm(taste ~ Lactic, data = cheddar[train.1,]) # comprobados supuestos
m2 <- lm(taste ~ Lactic, data = cheddar[train.2,])
m3 <- lm(taste ~ Lactic, data = cheddar[train.3,])
m4 <- lm(taste ~ Lactic, data = cheddar[train.4,])
m5 <- lm(taste ~ Lactic, data = cheddar[train.5,])


# Al igual que hicimos en 4 comprobamos si retirando outliers y observaciones influyentes mejoran las hipotesis.
#  Unicamente consideraremos observaciones obtenidas tanto por outlierTest() como por influencePlot().

# mh4
outlierTest(mh4)
influencePlot(mh4) # 6,12,15,24
pos4h <- c(rep(FALSE,5),TRUE,rep(FALSE,5),TRUE,rep(FALSE,2),TRUE,rep(FALSE,8),TRUE,rep(FALSE,6))

train.4inf <- train.4h&!pos4h
mh4inf <- lm(taste ~ H2S+Lactic, data = cheddar[train.4inf,])

ncvTest(mh4)
ncvTest(mh4inf) # mejora MUCHO

shapiro.test(resid(mh4))
shapiro.test(resid(mh4inf)) # mejora

durbinWatsonTest(mh4)
durbinWatsonTest(mh4inf) # mejora

resettest(mh4, power=2:3, type="regressor", data=cheddar[train.4inf,])
resettest(mh4inf, power=2:3, type="regressor", data=cheddar[train.4inf,]) # empeora pero es aceptable

# Redefinimos eliminando pos4h por ser tanta la mejora en homocedasticidad que compensa la linealidad
train.4h <- train.4inf
mh4 <- mh4inf


# mh5
outlierTest(mh5)
influencePlot(mh5) # 6,7,8,12,15
pos5h <- c(rep(FALSE,5),TRUE,TRUE,TRUE,rep(FALSE,3),TRUE,rep(FALSE,2),TRUE,rep(FALSE,15))

train.5inf <- train.5h&!pos5h
mh5inf <- lm(taste ~ H2S+Lactic, data = cheddar[train.5inf,])

ncvTest(mh5)
ncvTest(mh5inf) # mejora

shapiro.test(resid(mh5))
shapiro.test(resid(mh5inf)) # empeora

durbinWatsonTest(mh5)
durbinWatsonTest(mh5inf) # a veces no se cumple la hipotesis nula de no autocorrelacion

resettest(mh5, power=2:3, type="regressor", data=cheddar[train.5inf,])
resettest(mh5inf, power=2:3, type="regressor", data=cheddar[train.5inf,]) # empeora

# Decidimos no actualizar el modelo pues no siempre se rechaza la correlacion y empeoran otros p-valores.


# m2
outlierTest(m2)
influencePlot(m2) # 1,12,15,18,24
pos2 <- c(TRUE,rep(FALSE,10),TRUE,rep(FALSE,2),TRUE,rep(FALSE,2),TRUE,rep(FALSE,5),TRUE,rep(FALSE,6))

train.2inf <- train.2&!pos2
m2inf <- lm(taste ~ Lactic, data = cheddar[train.2inf,])

ncvTest(m2)
ncvTest(m2inf) # empeora ligeramente

shapiro.test(resid(m2))
shapiro.test(resid(m2inf)) # empeora ligeramente

durbinWatsonTest(m2)
durbinWatsonTest(m2inf) # empeora bastante

resettest(m2, power=2:3, type="regressor", data=cheddar[train.2inf,])
resettest(m2inf, power=2:3, type="regressor", data=cheddar[train.2inf,]) # mejora

# Decicimos no redefinirlo, ya que empeora en muchas y mejora bastante en una


# m3
outlierTest(m3)
influencePlot(m3) # 1,15,19,24
pos3 <- c(TRUE,rep(FALSE,13),TRUE,rep(FALSE,3),TRUE,rep(FALSE,4),TRUE,rep(FALSE,6))

train.3inf <- train.3&!pos3
m3inf <- lm(taste ~ Lactic, data = cheddar[train.3inf,])

ncvTest(m3)
ncvTest(m3inf) # mejora poco

shapiro.test(resid(m3))
shapiro.test(resid(m3inf)) # mejora

durbinWatsonTest(m3)
durbinWatsonTest(m3inf) # empeora

resettest(m3, power=2:3, type="regressor", data=cheddar[train.3inf,])
resettest(m3inf, power=2:3, type="regressor", data=cheddar[train.3inf,]) # empeora casi lo pierde

# Decidimos no redefinirlo por estar al borde en un criterio y no mejorar mucho en otros


# m4
outlierTest(m4)
influencePlot(m4) # 6,12,15,20,24
pos4 <- c(rep(FALSE,5),TRUE,rep(FALSE,5),TRUE,rep(FALSE,2),TRUE,rep(FALSE,4),TRUE,rep(FALSE,3),TRUE,rep(FALSE,6))

train.4inf <- train.4&!pos4
m4inf <- lm(taste ~ Lactic, data = cheddar[train.4inf,])

ncvTest(m4)
ncvTest(m4inf) # empeora bastante

shapiro.test(resid(m4))
shapiro.test(resid(m4inf)) # empeora

durbinWatsonTest(m4)
durbinWatsonTest(m4inf)# empeora bastante

resettest(m4, power=2:3, type="regressor", data=cheddar[train.4inf,])
resettest(m4inf, power=2:3, type="regressor", data=cheddar[train.4inf,]) # mejora algo

# Decidimos no cambiarlo porque empeora en casi todo, y de por si tenia buenos p-values


# m5
outlierTest(m5)
influencePlot(m5) # 1,8,12,15,18,24
pos5 <- c(TRUE,rep(FALSE,6),TRUE,rep(FALSE,3),TRUE,rep(FALSE,2),TRUE,rep(FALSE,2),TRUE,rep(FALSE,5),TRUE,rep(FALSE,6))

train.5inf <- train.5&!pos5
m5inf <- lm(taste ~ Lactic, data = cheddar[train.5inf,])

ncvTest(m5)
ncvTest(m5inf) # empeora bastante

shapiro.test(resid(m5))
shapiro.test(resid(m5inf)) # mejora

durbinWatsonTest(m5)
durbinWatsonTest(m5inf) # no se verifica la hipotesis nula de no autocorrelacion

resettest(m5, power=2:3, type="regressor", data=cheddar[train.5inf,])
resettest(m5inf, power=2:3, type="regressor", data=cheddar[train.5inf,]) # empeora

# Decidimos no cambiarlo por perderse la correlación

# Notese que en los originales siempre se cumplian las hipotesis, aunque no era necesario para el proceso




lista_test <- list(test.1,test.2,test.3,test.4,test.5)
lista_trainh <- list(train.1h,train.2h,train.3h,train.4h,train.5h)
lista_train <- list(train.1,train.2,train.3,train.4,train.5)


modelos_hip <- c("S1 taste ~ H2s + Lactic",
                 "S1 taste ~ Lactic",
                 "S2 taste ~ H2s + Lactic",
                 "S2 taste ~ Lactic",
                 "S3 taste ~ H2s + Lactic",
                 "S3 taste ~ Lactic",
                 "S4 taste ~ H2s + Lactic",
                 "S4 taste ~ Lactic",
                 "S5 taste ~ H2s + Lactic",
                 "S5 taste ~ Lactic",
                 "Nivel de significacion")

hip_RL <- c("Distribución_normal",
            "Media_0",
            "Varianza_no_constante",
            "No_Autocorrelación")
placeholder <- vector(mode = "logical",length = 11)
df_hipRL <- data.frame("0" = placeholder,
                       "1" = placeholder,
                       "2" = placeholder,
                       "3" = placeholder,
                       row.names = modelos_hip)

colnames(df_hipRL) <- hip_RL

r <- 1
for (dtrain in lista_trainh){
  model.HL.lm <- lm(taste ~ H2S + Lactic,
                    data = cheddar[dtrain,])
  residuos <- resid(model.HL.lm)
  new_row <- c()

  shap <- round(shapiro.test(residuos)$p.value,4)
  t <- t.test(residuos, mu = 0, alternative = "two.sided")$p.value
  v <- round(ncvTest(model.HL.lm)$p,4)
  dw <- round(durbinWatsonTest(model.HL.lm)$p,4)

  new_row = c(shap,t,v,dw)
  df_hipRL[r,] <- new_row
  r = r + 2
}


r <- 2
for (dtrain in lista_train){
  model.L.lm <- lm(taste ~Lactic,
                   data = cheddar[dtrain,])
  residuos <- resid(model.L.lm)
  new_row <- c()

  shap <- round(shapiro.test(residuos)$p.value,4)
  t <- t.test(residuos, mu = 0, alternative = "two.sided")$p.value
  v <- round(ncvTest(model.L.lm)$p,4)
  dw <- round(durbinWatsonTest(model.L.lm)$p,4)

  new_row = c(shap,t,v,dw)
  df_hipRL[r,] <- new_row
  r = r + 2
}
df_hipRL[11,] <- c(rep(0.05,4))
df_hipRL # Todos los modelos cumplen las hipótesis



err1 <- 0
for (i in 5){
  dtrain <- lista_trainh[[i]]
  dtest <- lista_test[[i]]
  dmod <- lm(taste ~ H2S + Lactic, data = cheddar[dtrain,])
  Y <- cheddar[dtest,]$taste
  Yhat <- predict(obj = dmod, newdata = cheddar[dtest,])
  err1 <- err1 + mean((Y - Yhat)^2)
}
err1 <- err1/5
err1 # H2S + LACTIC tiene error medio 11.63


err2<-0
for (i in 5){
  dtrain <- lista_train[[i]]
  dtest <- lista_test[[i]]
  dmod <- lm(taste ~ Lactic, data = cheddar[dtrain,])
  Y <- cheddar[dtest,]$taste
  Yhat <- predict(obj = dmod, newdata = cheddar[dtest,])
  err2 <- err2 + mean((Y - Yhat)^2)
}
err2 <- err2/5
err2 # LACTIC tiene error medio 19.4

err1 < err2 # Concluimos que el modelo taste ~ H2S + Lactic es mejor que taste ~ Lactic.





# 6) Conclusion

model.y <- lm(taste ~ H2S + Lactic,data=cheddar) # tomamos el mejor modelo de los obtenidos en 4
summary(model.y)
plot(model.y)

# Veamos los posibles outliers
outlierTest(model.y)
influencePlot(model.y)


# Estudio de hipótesis supuestas

shapiro.test(resid(model.y)) # normalidad de residuos
t.test(resid(model.y), mu = 0, alternative = "two.sided") # media cero de los residuos
ncvTest(model.y) # varianza constante de los residuos
durbinWatsonTest(model.y) # no autocorrelacion
resettest(model.y ,power=2:3, type="regressor", data=cheddar) # linealidad

# Efectivamente, cumple todas las hipótesis


summary(model.y) # en el summary observamos los valores de betahat, sus p-valores y sigma

coeff <- summary(model.y)$coeff[,1]
coeff

# Calculo de intervalo de confianza de beta1(H2S) y beta2(Lactic)

# Metodo Bonferroni
alpha <- 0.10
summary(model.y)$coef
b <- summary(model.y)$coef[2:3, 1]
s.b <- summary(model.y)$coef[2:3, 2]
g <- 3
n <- nrow(cheddar)
p <- ncol(summary(model.y)$coef)
t_teo <- qt(1 - alpha / (2 * g), n - p)
BomSimCI <- matrix(c(b - t_teo * s.b, b + t_teo * s.b), ncol = 2)
conf <- c("5%", "95%")
bnam <- c("H2S", "Lactic")
dimnames(BomSimCI) <- list(bnam, conf)
BomSimCI

# Intervalo de confianza simultaneo por el metodo de Scheffe
Q <- p - 1
f_teo <- qf(0.9, Q, n - p)#0.9 no seria 0.95?
SchSimCI <- matrix(c(b - sqrt(Q * f_teo) * s.b, b + sqrt(Q * f_teo) * s.b), ncol = 2)
conf <- c("5%", "95%")
bnam <- c("H2S", "Lactic")
dimnames(SchSimCI) <- list(bnam, conf)
SchSimCI


# La ecuación de nuestro modelo final es y = (-27.6) + 3.95*x_H + 19.9*x_L,
#    donde x_H y x_L denotan los valores observados de H2S y Lactic.


rse <- sqrt(deviance(model.y)/df.residual(model.y))
rse  # varianza de los residuos

pval <- summary(model.y)$coeff[,4]
pval  # vector con los p-valores


# Calculo de su R^2
anova(model.y)
SSE <- anova(model.y)[3,2]
SST <- anova(model.y)[1,2]+anova(model.y)[2,2]+anova(model.y)[3,2]
rsqr <- 1 - SSE/SST
rsqr
summary(model.y)$r.squared# es la misma

# Calculo de su R^2 ajustada
MSE <- SSE/anova(model.y)[3,1]
MST <- SST/(anova(model.y)[1,1]+anova(model.y)[2,1]+anova(model.y)[3,1])
Radj <-1-MSE/MST
Radj  # se comprueba en la tabla summary que el valor es correcto


# Observamos como se distribuye la variable taste en función de H2S y Lactic
plot_ly(x=H2S, y=Lactic, z=taste, type="scatter3d", mode="marker", color=taste) %>%
  layout(scene = list(xaxis = list(title = 'H2S (%)'),
                      yaxis = list(title = 'Lactic (%)'),
                      zaxis = list(title = 'Taste (0-100)')))


# Vemos el plano de regresion del modelo propuesto.
# En rojo se marcan las observaciones que peor se ajustan al modelo.
planereg <- scatterplot3d(x=H2S, y=Lactic, z=taste, pch=16, cex.lab=1,
                          highlight.3d=TRUE, type="h", xlab='H2S (%)',
                          ylab='Lactic (%)', zlab='Taste (0-100)')
planereg$plane3d(model.y, lty.box="solid", col='mediumblue')
LS0tDQp0aXRsZTogJ1JlZ3Jlc2nDs246IE1vZGVsb3MgRXN0YWTDrXN0aWNvcycNCmF1dGhvcjoNCi0gRGFuaWVsIEzDs3BleiBNb250ZXJvDQotIFJvZHJpZ28gZGUgbGEgTnVleiBNb3JhbGVkYQ0KLSBKb3PDqSBHYXJjw61hIFJlYm9sbG8NCi0gRGF2aWQgUGFycm8gUGxhemEgDQpvdXRwdXQ6DQogIHBkZl9kb2N1bWVudDoNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzMnDQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCmFsd2F5c19hbGxvd19odG1sOiB5ZXMNCmFic3RyYWN0OiB8DQogIEhlbW9zIGFuYWxpemFkbyBjb24gbGFzIGhlcnJhbWllbnRhcyBwcm9wb3JjaW9uYWRhcyBlbiBlbCBjdXJzbyBkZSBNb2RlbG9zIEVzdGFkw61zdGljb3MgZWwgY29uanVudG8gZGUgZGF0b3MsICpDaGVkZGFyKiwgZGlzdHJpYnVpZG8gZW4gbGEgbGlicmVyw61hIEZhcmF3YXkgZGUgUi4gUGFyYSBlbGxvIGhlbW9zIHV0aWxpemFkbyBkaXZlcnNhcyB0w6ljbmljYXMgZGUgcmVncmVzacOzbiBsaW5lYWwuDQpzdWJ0aXRsZTogJ0Nvbmp1bnRvIGRlIERhdG9zOiBDaGVkZGFyIEZhcmF3YXknDQotLS0NCg0KDQojIEludHJvZHVjY2nDs24NCg0KRW4gdW4gZXN0dWRpbyBkZSBxdWVzbyBDaGVkZGFyIHJlYWxpemFkbyBlbiBlbCBWYWxsZSBkZSBMYXRyb2JlIChWaWN0b3JpYSwgQXVzdHJhbGlhKSwgc2UgZXN0dWRpYXJvbiBtdWVzdHJhcyBkZSBxdWVzbyBlbiBsYXMgcXVlIHNlIGFuYWxpesOzIHN1IGNvbXBvc2ljacOzbiBxdcOtbWljYSB5IGZ1ZXJvbiBkYWRhcyBhIHByb2JhciBhIGRpc3RpbnRvcyBzdWpldG9zIHBhcmEgcXVlIHZhbG9yYXJhbiBzdSBzYWJvci4gTG9zIHZhbG9yZXMgYXNpZ25hZG9zIGEgY2FkYSBxdWVzbyBzb24gZWwgcmVzdWx0YWRvIGRlIGNvbWJpbmFyIGxhcyBkaXN0aW50YXMgdmFsb3JhY2lvbmVzLiANCg0KRWwgRGF0YUZyYW1lICoqY2hlZGRhcioqIGRlIGxhIGxpYnJlcsOtYSAqKmZhcmF3YXkqKiBjb25zaXN0ZSBkZSAzMCBtdWVzdHJhcyBkZSBxdWVzbyBDaGVkZGFyIGVuIGxhcyBxdWUgc2UgaGEgbWVkaWRvIGVsIHNhYm9yICgqdGFzdGUqKSB5IGxhcyBjb25jZW50cmFjaW9uZXMgZGUgw6FjaWRvIGFjw6l0aWNvICgqQWNldGljKiksIMOhY2lkbyBzdWxmaMOtZHJpY28gKCpIMlMqKSB5IGxhY3Rvc2EgKCpMYWN0aWMqKS4NCg0KDQpUZW5lbmVtb3MgdW4gY29uanVudG8gZGUgZGF0b3MgZW4gZWwgcXVlIHNlIHJlY29nZW4gb2JzZXJ2YWNpb25lcyBkZSB1bmEgY2F0YSBkZQ0KcXVlc29zLCBudWVzdHJhcyB2YXJpYWJsZXMgc29uOiAgIA0KDQoNCioqwrcgVGFzdGU6KiogdW5hIHZhbG9yYWNpw7NuIHN1YmpldGl2YSBkZSBsb3MganVlY2VzLiAgIA0KDQoqKsK3IEFjZXRpYzoqKiBsYSBjb25jZW50cmFjacOzbiBkZSDDoWNpZG8gYWPDqXRpY28uDQoNCioqwrcgSDJTOioqIGxhIGNvbmNlbnRyYWNpw7NuIGRlIHN1bGZpdG8gZGUgaGlkcsOzZ2Vuby4NCg0KKirCtyBMYWN0aWM6KiogY29uY2VudHJhY2nDs24gZGUgw6FjaWRvIGzDoWN0aWNvLg0KDQogPCEtLSBBIGxvIGxhcmdvIGRlbCBkb2N1bWVudG8gaGFjZW1vcyB1c28gZGUgbGFzIHNpZ3VpZW50ZXMgbGlicmVyaWFzIGRlIFI6IC0tPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCmxpYnJhcnkoZmFyYXdheSkNCmxpYnJhcnkobGVhcHMpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KFBBU1dSKQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBseXIpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoc2NhdHRlcnBsb3QzZCkNCmxpYnJhcnkobG10ZXN0KQ0KbGlicmFyeShtaXhsbSkNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGxlbW9uKQ0KbGlicmFyeShicm9vbSkNCmxpYnJhcnkodGliYmxlKQ0KYGBgDQoNCkNhcmdhbW9zIGxvcyBkYXRvcyB5IGVuc2XDsWFtb3MgbGFzIHByaW1lcmFzIG9ic2VydmFjaW9uZXMuDQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnR9DQojIGxvYWQgY2hlZGRhciBjaGVkZGFyDQpkYXRhKGNoZWRkYXIpIA0KaGVhZChjaGVkZGFyKQ0KYGBgDQoNClNpIGVuIG51ZXN0cm8gZGF0YXNldCB0dXZpZXNlbW9zIGVudHJhZGFzIHZhY8OtYXMgKE5BKSwgdGVuZW1vcyB2YXJpYXMgcG9zaWJpbGlkYWRlcyBwYXJhIGxpZGlhciBjb24gZXN0ZSBwcm9ibGVtYToNCg0KKiBObyB1dGlsaXphci9FbGltaW5hciBsYXMgb2JzZXJ2YWNpw7NuIHF1ZSBjb250aWVuZW4gdmFsb3Jlcy4NCg0KKiBObyB1dGlsaXphci9FbGltaW5hciBsYXMgdmFyaWFibGVzIHF1ZSBjb250aWVuZW4gbGFzIGVudHJhZGFzIHZhY8OtYXMuDQoNCiogSW50ZW50YXIgY29tcGxldGFyIGxvcyB2YWxvcmVzLiBFeGlzdGVuIG3DqXRvZG9zIG1lbm9zIHkgbcOhcyBzb2Zpc2l0Y2Fkb3M6DQoNCiAgKyBSZW1wbGV6YXIgY29uIGxhICoqbWVkaWEsIG1lZGlhIG8gbW9kYSoqLg0KDQogICsgQ3JlYXIgdW5hICoqbnVldmEgY2F0ZWdvcsOtYSoqIHBhcmEgdmFsb3JlcyB2YWPDrW9zLg0KDQogICsgVXRpbGl6YXIgYWxnw7puIG1vZGVsbyBkZSAqKnJlZ3Jlc2nDs24qKi4NCg0KICArIFVzYXIgdW4gbW9kZWxvIGRlICoqSy1OZWFyZXN0IE5laWdoYm9ycyAoS05OKSoqLg0KICANClBlcm8gZW4gbnVlc3RybyBjYXNvIGV2YWx1YW1vcyB5IG5vIGhheSB2YWxvcmVzICptaXNzaW5nKi4gIA0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KIyBjaGVjayBpZiBhbnkgZW50cnkgaGFzIGEgbWlzc2luZyB2YWx1ZSAoTkEpDQphbnkoaXMubmEoY2hlZGRhcikpDQpgYGANCg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0Kc2FwcGx5KGNoZWRkYXIsIGNsYXNzKQ0KYGBgDQoNCkVuIG51ZXN0cm8gY2FzbywgdG9kYXMgbGFzIHZhcmlhYmxlcyBzb24gbnVtw6lyaWNhcyAoKipjdWFudGl0YXRpdmFzKiopLiBObyBoYXkgbmluZ3VuYSB2YXJpYWJsZSBjYXRlZ8OzcmljYSBuaSBjdWFsaXRhdGl2YS4gU2kgaHViaWVzZSwgdGVuZHLDrWFtb3MgcXVlIHRyYW5zZm9ybWFybGFzIGVuIHZhcmlhYmxlcyBiaW5hcmlhcy4gUGFyYSBlbGxvLCBkZWJlcsOtYW1vcyBoYWNlciBlbmNvZGluZyBhIHZhcmlhYmxlcyBiaW5hcmlhcywgZWwgbGVuZ3VhamUgZGUgcHJvZ3JhbWFjacOzbiBSIG5vcyBwZXJtaXRlIHV0aWxpemFyICphcy5udW1lcmljKi4NCg0KQ29uIGVzdGFzIHZhcmlhYmxlcyB2YW1vcyBhIGludGVudGFyICoqZXhwbGljYXIqKiBjw7NtbyBsb3MgdmFsb3JlcyBvYnNlcnZhZG9zIGRlIHVuYSB2YXJpYWJsZSBZICh0YXN0ZSkgZGVwZW5kZW4gZGUgbG9zIHZhbG9yZXMgZGUgb3RyYXMgdmFyaWFibGVzIChBY2V0aWMsIEgyUywgTGF0Y2ljKSwgYSB0cmF2w6lzIGRlIHVuYSByZWxhY2nDs24gZnVuY2lvbmFsIGxpbmVhbCBkZWwgdGlwbyBZID0gZihYKS4NClRhbWJpw6luIHZhbW9zIGEgaW50ZW50YXIgKipwcmVkZWNpcioqIGVsIHZhbG9yIGRlIGxhIHZhcmlhYmxlIFkgcGFyYSB2YWxvcmVzIG5vIG9ic2VydmFkb3MgZGUgbGFzIHZhcmlhYmxlcyBYLg0KDQoNClRlbmVtb3MgMzAgb2JzZXJ2YWNpb25lcyBlbiBudWVzdHJvIGRhdGFzZXQuIEFob3JhIHByb2NlZGVtb3MgYSBkaXZpcmxvIGVuIGVsICpjb25qdW50byBkZSB0cmFpbiB5IHRlc3QqLiBFbCBwcmltZXJvIGxvIHV0aWxpemFyZW1vcyBwYXJhIGVudHJlbmFyIG51ZXN0cm9zIG1vZGVsb3MgeSBlbCBzZWd1bmRvIGxvIHVzYXJlbW9zIHBhcmEgY3VhbnRpZmljYXIgZWwgZXJyb3IgZGUgbG9zIG1vZGVsb3MuDQoNCg0KUGFyYSBhc2VndXJhciBxdWUgc2VhIHJlcHJvZHVjaWJsZSB1dGlsaXphbW9zIHVuYSBzZW1pbGxhLCBxdWUgcGVybWl0ZSBmaWphciBsb3MgdmFsb3JlcyBwc2V1ZG9hbGVhdG9yaW9zIG9idGVuaWRvcyBlbiBtdWNoYXMgZGUgbGFzIGZ1bmNpb25lcyB1dGlsaXphZGFzLg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCiMgUGFyYSBhc2VndXJhciBxdWUgc2VhIHJlcHJvZHVjaWJsZSB1dGlsaXphbW9zIHVuYSBzZW1pbGxhLCBxdWUgcGVybWl0ZSBmaWphciBsb3MgdmFsb3JlcyBwc2V1ZG9hbGVhdG9yaW9zIG9idGVuaWRvcyBlbiBtdWNoYXMgZGUgbGFzIGZ1bmNpb25lcyB1dGlsaXphZGFzLg0Kc2V0LnNlZWQoMSkNCnRyYWluIDwtIHNhbXBsZShjKFRSVUUsIEZBTFNFKSwNCiAgICAgICAgICAgICAgICBzaXplID0gbnJvdyhjaGVkZGFyKSwNCiAgICAgICAgICAgICAgICByZXBsYWNlID0gVFJVRSwNCiAgICAgICAgICAgICAgICBwcm9iID0gYygwLjcsIDAuMykpDQp0ZXN0IDwtICF0cmFpbg0KYGBgDQoNCkhhY2Vtb3MgdW4gZXN0dWRpbyBwcmVsaW1pbmFyIGRlIG51ZXN0cmFzIHZhcmlhYmxlcy4gTW9zdHJhbW9zIHVuIHNjYXR0ZXIgcGxvdCBkZSBjYWRhIHZhcmlhYmxlIGNvbnRyYXN0YWRhIGNvbiBlbCByZXN0by4gRXN0byBwZXJtaXRlIHZlciAqYSBvam8qIHNpIGFsZ8O6biBwYXIgZGUgdmFyaWFibGVzIHRpZW5lIGNvcnJlbGFjacOzbi4gIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCxmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTR9DQpwbG90KGNoZWRkYXIpDQpgYGANCiAgDQogIEFob3JhLCB1dGlsaXphbW9zIGxhIGZ1bmNpw7NuICpzdW1tYXJ5KiBkZSBSLCBsYSBjdWFsIG5vcyBwZXJtaXRlIGVzdGltYXIgYWxndW5vcyBkZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBsYSBkaXN0cmlidWNpw7NuIGRlbCBkYXRhc2V0LiBMYSBzaWd1aWVudGUgdGFibGEgbm9zIG11ZXN0cmEgbG9zIGVzdGFkw61zdGljb3MgbcOhcyBjb211bmVzOiBlbCBtw61uaW1vLCBtw6F4aW1vLCBtZWRpYW5hLCBtZWRpYSB5IGVsIDFlciB5IDNlciBjdWFydGlsLiANCg0KDQpgYGB7ciBmaWcud2lkdGg9NSwgaW5jbHVkZT1GQUxTRX0NCmRmX3Jlc3VtZW4gPC0gdGlkeShjaGVkZGFyKSAjIERpc3RyaWJ1Y2nDs24gZGUgbGFzIHZhcmlhYmxlcw0KDQoNCg0KDQpgYGANCjxicj4NCjxicj4NCjxicj4NClByZXNlbnRhbW9zIGVsIG1vZGVsbzoNCmBgYHtyIGVjaG89RkFMU0UsIHJlbmRlcj1sZW1vbl9wcmludH0NCmRhdGEuZnJhbWUobGFwcGx5KGRmX3Jlc3VtZW4sIGZ1bmN0aW9uKHkpIGlmKGlzLm51bWVyaWMoeSkpIHJvdW5kKHksIDIpIGVsc2UgeSkpDQoNCg0KYGBgDQoNCg0KDQpgYGB7ciBBdHRhY2gsIGluY2x1ZGU9RkFMU0V9DQphdHRhY2goY2hlZGRhcikNCmBgYA0KDQoNCkhhY2Vtb3MgbGFzIGdyw6FmaWNhcyBkZSBkaXNwZXJzacOzbiBlbnRyZSBsYSB2YXJpYWJsZSByZXNwdWVzdGEgKnRhc3RlKiB5IGxhcyB2YXJpYWJsZXMgcHJlZGljdG9yYXMgKkFjZXRpYywgSDJTLCBMYWN0aWMqLg0KDQpgYGB7ciBlY2hvPUZBTFNFLGZpZy53aWR0aD03LGZpZy5oZWlnaHQ9M30NCmxheW91dChtYXRyaXgoMTozLCBucm93ID0gMSkpDQojIHBsb3QgdGFzdGUgfiBBY2V0aWMNCnBsb3QoQWNldGljLCB0YXN0ZSwNCiAgICAgbWFpbiA9ICJSZWxhY2nDs24gZW50cmUgVGFzdGUgeSBBY2V0aWMiLA0KICAgICB4bGFiID0gIkFjZXRpYyIsIHlsYWIgPSAiVGFzdGUiLA0KICAgICBwY2ggPSAxOSwgZnJhbWUgPSBGQUxTRSkNCiMgcGxvdCB0YXN0ZSB+IEgyUw0KcGxvdChIMlMsIHRhc3RlLA0KICAgICBtYWluID0gIlJlbGFjacOzbiBlbnRyZSBUYXN0ZSB5IEgyUyIsDQogICAgIHhsYWIgPSAiSDJTIiwgeWxhYiA9ICJUYXN0ZSIsDQogICAgIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFKQ0KIyBwbG90IHRhc3RlIH4gTGFjdGljDQpwbG90KExhY3RpYywgdGFzdGUsDQogICAgIG1haW4gPSAiUmVsYWNpw7NubiBlbnRyZSBUYXN0ZSB5IExhY3RpYyIsDQogICAgIHhsYWIgPSAiTGFjdGljIiwgeWxhYiA9ICJUYXN0ZSIsDQogICAgIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpsYXlvdXQobWF0cml4KDE6MSwgbnJvdyA9IDEpKQ0KYGBgDQoNClBvZGVtb3Mgb2JzZXJ2YXIgcXVlIGxhIHF1ZSBhcGVyZW50ZW1lbnRlIGd1YXJkYSB1bmEgbWVub3IgcmVsYWNpw7NuIGxpbmVhbCBjb24gdGFzdGUgZXMgbGEgdmFyaWFibGUgQWNldGljLCBlc3RlIGhlY2hvIHNlcsOhIHJlYWZpcm1hZG8gbcOhcyBhZGVsYW50ZS4NCg0KDQojIEVzdHVkaW8geSBldmFsdWFjacOzbiBkZWwgbW9kZWxvIGNvbXBsZXRvLiAgDQoNCkludGVudGFyZW1vcyBwcmVkZWNpciBsYSB2YXJpYWJsZSAqdGFzdGUqIHVzYW5kbyBlbCByZXN0byBkZSB2YXJpYWJsZXMuIFBhcmEgZW1wZXphciwgZGVmaW5pbW9zIGVsIG1vZGVsbyBjb21wbGV0bywgZWwgY3VhbCBzZSB1c2FuIHRvZGFzIGxhcyB2YXJpYWJsZXMgcGFyYSBudWVzdHJvIG1vZGVsbyBsaW5lYWwgbcO6bHRpcGxlLg0KDQokJA0KWV9pID1cYmV0YV8wICsgXGJldGFfMSB4X3tpMX0gKyBcZG90cyArIFxiZXRhX3twLTF9eF97aShwLTEpfSArIFxlcHNpbG9uX2ksXHF1YWQgaT0xLFxkb3RzLG4NCiQkDQpkb25kZSAkWV9pJCBlcyBlbCB2YWxvciBkZSBsYSB2YXJpYWJsZSByZXNwdWVzdGEgcGFyYSBlbCBpbmRpdmlkdW8gJGkkLcOpc2ltbywgDQokXGJldGFfMCQgeSBsb3MgJFxiZXRhX2okIHNvbiBsb3MgcGFyw6FtZXRyb3MgJGogPSAxLCAuLi4sIHAgLSAxJCwgDQokeF97aWp9JCBzb24gbG9zIGVsZW1lbnRvcyBkZSBsYSBtYXRyaXogZGUgbGFzIHZhcmlhYmxlcyBleHBsaWNhdGl2YXMgDQokXGVwc2lsb25faSQgZXMgZWwgdMOpcm1pbm8gZGVsIGVycm9yIGFsZWF0b3JpbyBxdWUgc3Vwb25lbW9zIHF1ZSBzZSBkaXN0cmlidXllIGNvbW8gdW5hICRcbWF0aGNhbHtOfSgwLFxzaWdtYV4yKSQsIGRvbmRlICRcc2lnbWFeMiQgZXMgbGEgdmFyaWFuemEgcXVlIHN1ZWxlIHNlciBkZXNjb25vY2lkYS4NCg0KIyMgUmVzb2x1Y2nDs24gbWVkaWFudGUgbWF0cmljZXMNCg0KVXRpbGl6YW1vcyBlbCBtw6l0b2RvIGRlIG3DrW5pbW9zIGN1YWRyYWRvcyBxdWUgZXN0aW1hIGxvcyB2YWxvcmVzICRcaGF0e1xiZXRhfSQgaW50ZW50YW5kbyBtaW5pbWl6YXIgbG9zIGVycm9yZXMgJFxlcHNpbG9uJC4gQ29tbyBoZW1vcyB2aXN0byBlbiBjbGFzZSwgbGEgZsOzcm11bGEgcXVlIHNlIGRlZHVjZSBlczoNCg0KJCQgDQpcaGF0e1xiZXRhfSA9IChYXnRYKV57LTF9WF50WQ0KJCQNCmRvbmRlICRYJCBlcyB1bmEgY29sdW1uYSBkZSAxJ3MgY29uY2F0ZW5hZGEgY29uIGxhcyB2YXJpYWJsZXMgcXVlIHVzYW1vcyBwYXJhIHByZWRlY2lyLg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KeCA8LSBtb2RlbC5tYXRyaXgoIH4gQWNldGljICsgSDJTICsgTGFjdGljLCBkYXRhID0gY2hlZGRhcikNCmJldGFoYXQgPC0gc29sdmUoY3Jvc3Nwcm9kKHgsIHgpLCBjcm9zc3Byb2QoeCwgdGFzdGUpKQ0KYmV0YWhhdCA8LSBjKGJldGFoYXQpDQpiZXRhaGF0DQpgYGANClBvciB0YW50bywgYXByb3hpbWFtb3MgbGFzICRcYmV0YSQgbW9kZWxvIGxpbmVhbCBjb21wbGV0byBjb24gbG9zIHZhbG9yZXMgZGUgJFxoYXR7XGJldGF9XzAsXGRvdHMsXGhhdHtcYmV0YX1fMyQgY29uIGxvcyBzaWd1aWVudGVzIHZhbG9yZXM6DQoNCiQkDQpcaGF0e1xiZXRhfV8wPS0yOC44NzY3Njk2LFxxdWFkXGhhdHtcYmV0YX1fMT0wLjMyNzc0MTMsXHF1YWRcaGF0e1xiZXRhfV8yPTMuOTExODQxLFxxdWFkXGhhdHtcYmV0YX1fMz0xOS42NzA1NDM0DQokJA0KDQojIyBSZXNvbHVjacOzbiB1c2FuZG8gbGlicmVyaWFzIGRlIFINCg0KUG9kZW1vcyB1dGlsaXphciBsYSBmdW5jacOzbiAkbG0kLCB5YSBwcm9ncmFtYWRhIGVuIFIuIERlZmluaW1vcyBlbCBtb2RlbG8gY29tcGxldG8sIHkgY29tcHJvYmFtb3MgbGFzIGJldGFzOg0KDQokJA0KdGFzdGUgXHNpbSBBY2V0aWMgXCwgKyBcLCBIMlMgXCwgKyBcLCBMYWN0aWMsIFwsICBcLCBkYXRhID0gY2hlZGRhcg0KJCQNCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KbW9kZWwuYWxsLmxtIDwtIGxtKHRhc3RlIH4gLiwgZGF0YSA9IGNoZWRkYXIpDQoNCmZpbGFfY29lZiA8LSB2ZWN0b3IoKQ0KZGZfYW5vdmEgPC0gZGF0YS5mcmFtZSgiMSIgPSAxLCAiMiIgPSAyLCIzIiA9IDMsIjQiPTQsIHJvdy5uYW1lcyA9ICJDb2VmaWNpZW50ZXMiKQ0KY29sbmFtZXMoZGZfYW5vdmEpIDwtIGMoIkludGVyY2VwdCIsIkFjZXRpYyIsIkgyUyIsIkxhY3RpYyIpDQoNCmZvcihpIGluIDE6NCl7DQpmaWxhX2NvZWYgPC0gYyhmaWxhX2NvZWYsbW9kZWwuYWxsLmxtJGNvZWZmaWNpZW50c1tbaV1dKSAgDQp9DQoNCmRmX2Fub3ZhWzEsXSA8LSBmaWxhX2NvZWYNCmRmX2Fub3ZhDQoNCmBgYA0KDQoNCkVzdHVkaWVtb3MgcHJlbGltaW5hcm1lbnRlIHNpIGVzIHVuIG1vZGVsbyBsaW5lYWwgYWRlY3VhZG8sIHBhcmEgZWxsbyANCmNvbXByb2JhcmVtb3MgbGFzIGhpcMOzdGVzaXMgZXN0w6FuZGFyIGRlbCBtb2RlbG8gbGluZWFsIGRlIHJlZ3Jlc2nDs24gdXNhbmRvIGVsICoqdGVzdCBkZSBub3JtYWxpZGFkIFNoYXBpcm8tV2lsayoqLiBMYSBmdW5jacOzbiAkc2hhcGlyby50ZXN0JCBsZSBwYXNhbW9zIHBvciBwYXLDoW1ldHJvIGVsIHJlc2lkdW8vZXJyb3IgZGUgY2FkYSB1bmEgZGUgbGFzIG11ZXN0cmFzIHkgbm9zIGRldnVlbHZlIHVuICRwJC12YWxvci4NCg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLmFsbC5sbSkpDQpgYGANCk9ic2VydmFtb3MgcXVlIGVzdGFtb3MgZW4gbGEgaGlww7N0ZXNpcyBkZSBxdWUgZWwgZXJyb3IgbnVlc3RybyBtb2RlbG8gc2UgZGlzdHJpYnV5ZSBkZSBtYW5lcmEgbm9ybWFsLCB5YSBxdWUgZWwgcC12YWxvciBlcyAkMC44ODY1ID4gMC4wNSQuIA0KDQpPdHJvIGFzcGVjdG8gcXVlIGRlYmVtb3Mgc2FiZXIgZXMgc2kgbGEgbWVkaWEgZGUgbG9zIGVycm9yZXMgc2Vyw6EgbnVsYSBvIG5vLCBwYXJhIGVsbG8gdXNhbW9zIHVuYSBmdW5jacOzbiBpbXBsZW1lbnRhZGEgZW4gUiBxdWUgbm9zIGFmaXJtYSBxdWUgZW4gbnVlc3RybyBjYXNvIGVzdG8gZXMgYXPDrS4gUmVzcGVjdG8gYSBsb3MgZXJyb3JlcyB0ZW5lbW9zIHF1ZSBzYWJlciBxdWUgc2UgZGlzdHJpYnV5ZW4gY29uIHZhcmlhbnphIGNvbnN0YW50ZSwgcXVlIGRlIG1hbmVyYSBhbsOhbG9nYSBjb21wcm9iYW1vcywgdGVuaWVuZG8gcC12YWxvcmVzIGxvIHN1ZmljaWVudGVtZW50ZSBiYWpvcyBjb21vIHBhcmEgcmVjaGF6YXIgdmFyaWFuemEgbm8gY29uc3RhbnRlLg0KIERlIGlndWFsIG1hbmVyYSB0ZW5lbW9zIHF1ZSBubyBoYXkgYXV0b2NvcnJlbGFjacOzbiBlbiBlbCBtb2RlbG8gY29tcGxldG8uDQoNClVuYSB2ZXogaGVtb3MgY29uY2x1aWRvIHF1ZSBhdW5xdWUgZXN0YW1vcyBlbiBsYXMgaGlww7N0ZXNpcyBkZSByZWdyZXNpw7NuIGxpbmVhbA0KZWwgbW9kZWxvIGNvbXBsZXRvIGEgcGVzYXIgZGUgc2VyIGVsIG3DoXMgY29tcGxlam8gcHJvYmFibGVtZW50ZSBkYSByZXN1bHRhZG9zIA0Kc2ltaWxhcmVzIGEgb3RybyBtw6FzIHNpbXBsZS4NCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmRmX3Jlc3VtZW4gPC0gdGlkeShtb2RlbC5hbGwubG0pDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KZGZfcmVzdW1lbg0KYGBgDQoNClRyYXMgcmVhbGl6YXIgZWwgc3VtbWFyeSBkZWwgbW9kZWxvLCB1bmEgb2JzZXJ2YWNpw7NuIG11eSBpbXBvcnRhbnRlIHF1ZSBzYWNhbW9zIGVzIHF1ZSBlbCBwLXZhbG9yIGRlIEFjZXRpYyBlcyBtdXkgZ3JhbmRlICgwLjk0KSBwb3IgbG8gcXVlIG5vIHZhIGEgc2VyIHVuYSB2YXJpYWJsZSBzaWduaWZpY2F0aXZhIHkgcG9yIHRhbnRvIGNvbiBjYXNpIHRvZGEgc2VndXJpZGFkIG5vIHRpZW5lIGltcGFjdG8gcmVhbCBlbiBlbCBtb2RlbG8uDQoNClBvciBlbCBjb250cmFyaW8gZWwgcmVzdG8gZGUgdmFyaWFibGVzIHPDrSBzb24gc2lnbmlmaWNhdGl2YXMgcG9yIHRlbmVyIHAtdmFsb3IgaW5mZXJpb3IgYSAwLjUsIGRlc3RhY2FuZG8gTGFjdGljIHBvciB0ZW5lciB1biBiZXRhIG1heW9yIHF1ZSBIMlMsIGxvIHF1ZSBwcHVlZGUgaGFjZXJub3MgbGxlZ2FyIGEgcGVuc2FyIHF1ZSBjb2JyZSBtw6FzIGltcG9ydGFuY2lhIGVuIHVuIG1vZGVsbyBmaW5hbC4gIA0KDQojIyMjIENvcnJlbGFjaW9uZXMgeSB0YWJsYSBkZSByZXN1bHRhZG9zIGNvbiBlbCBlc3R1ZGlvIGRlIHN1cyBwLXZhbG9yZXMgIA0KDQpVc2Ftb3MgZWwgcGFxdWV0ZSAkR0dwbG90JCBkZSBSLCBlbCBjdWFsIG5vcyBwZXJtaXRlIHZpc3VhbGl6YXIgbGEgY29ycmVsYWNpw7NuIHkgZGlzcGVyc2nDs24gZW50cmUgbGFzIGRpc3RpbnRhcyB2YXJpYWJsZXMuDQoNCmBgYHtyIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9My41LCBmaWcud2lkdGg9NywgbWVzc2FnZT1GQUxTRX0NCmNvcnBsb3QgPC0gZ2dwYWlycyhjaGVkZGFyW3RyYWluLF0sIHByb2dyZXNzPUZBTFNFKQ0KY29ycGxvdCANCmBgYA0KDQpQZGVtb3MgYXByZWNpYXIgcXVlIGxhIHZhcmlhYmxlIGNvbiBtZW5vciBjb2VmZWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gZGUgUGVhcnNvbiBlcyBBY2V0aWMsbWllbnRyYSBxdWUgZWwgcmVzdG8gZGUgdmFyaWFibGVzIHRpZW5lbiAgdW4gdmFsb3IgYmFzdGFudGUgbWF5b3IuIENhYmUgZGVzdGFjYXIgcXVlIHRvZG9zIHRpZW5lbiB1biBzaWdubyBwb3NpdGl2bywgbG8gcXVlIG5vcyBkaWNlIHF1ZSBlbiBnZW5lcmFsIGFsIGF1bWVudGFyIHVuYSBhdW1lbnRhIGxhIG90cmEuDQoNCg0KIyMgwr9UaWVuZSAqb3V0bGllcnMqIG51ZXN0cmEgbXVlc3RyYT8NCg0KUGFyYSBjb21wcm9iYXJsbyBiYXN0YSByZWFsaXphciBlbCAqKnRlc3QgZGUgQm9uZmVycm9uaSoqIHNvYnJlIG51ZXN0cm8gbW9kZWxvIGNvbXBsZXRvOg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0Kb3V0bGllclRlc3QobW9kZWwuYWxsLmxtKQ0KYGBgDQoNCg0KQ29uY2x1aW1vcyBjb24gdW4gbml2ZWwgJFxhbHBoYSQgPSAwLjA1IHF1ZSBubyB0ZW5lbW9zIG5pbmfDum4gb3V0bGllciBlbiBudWVzdHJhLiBMbyBtw6FzIGNlcmNhbm8gYSB1biAqb3V0bGllciogcXVlIHRlbmVtb3MgZXMgbGEgb2JzZXJ2YWNpw7NuIG7Dum1lcm8gMTUsIHF1ZSB0aWVuZSB1biB2YWxvciAqKkJvbmZlcnJvbmkgcCoqIGRlIDAuMTc0NTMgKG5vIHNlIGFjZXJjYSBhIDAuMDUpLiBQb3IgdGFudG8sIG5vIHRlbmVtb3MgcmF6b25lcyBwb3IgbGFzIHF1ZSBlbGltaW5hciBhbGd1bmEgb2JzZXJ2YWNpw7NuIGludXN1YWwgZGUgbnVlc3RybyBjb25qdW50byBkZSBkYXRvcy4gDQoNCkVzdG8gc2UgcHVlZGUgY29tcHJvYmFyIGdyYWZpY2FtZW50ZSBhIHRyYXbDqXMgZGVsIHNpZ3VpZW50ZSBncsOhZmljbywgZWwgY3VhbCBtaWRlIGxhIGluZmx1ZW5jaWEgZGUgY2FkYSBvYnNlcnZhY2nDs24gc29icmUgY2FkYSB1bmEgZGUgbGFzIGJldGFzIGRlIG51ZXN0cm8gbW9kZWxvLiANCg0KYGBge3IgZWNobz1GQUxTRSwgZmlnLmhlaWdodD0zLjZ9DQppbmZsdWVuY2VJbmRleFBsb3QobW9kZWwuYWxsLmxtKQ0KYGBgDQoNClZlbW9zIHF1ZSBsYSBxdWUgbcOhcyBpbmZsdXllIGVzIGxhIGFudGVzIG1lbmNpb25hZGEgb2JzZXJ2YWNpw7NuIDE1IHkgcG9yIHRhbnRvIGRlYmVyw61hbW9zIGNvbnNpZGVyYXIgc2kgZXMgb3V0bGllci4gSGVtb3MgY29tcHJvYmFkbyBxdWUgc3VjZWRlcsOtYSBhbCBlbGltaW5hciBlc2Egb2JzZXJ2YWNpw7NuIGRlIGxhIG11ZXN0cmEsIHkgc2kgYmllbiBtZWpvcmFiYSBhbGfDum4gcC12YWxvciBkZSBsYXMgaGlww7N0ZXNpcyBkZSByZWdyZXNpw7NuLCBlbiBvdHJvcyBsb3MgZW1wZW9yYWJhLCBhc8OtIHF1ZSBoZW1vcyBkZWNpZGlkbyBubyBlbGltaW5hcmxhIHkgZXNwZXJhcm5vcyBhIHZlciBlbCBjYXNvIGVuIGxhcyBzZWVkcyBxdWUgZXN0dWRpYXJlbW9zIGNvbiBtw6FzIGRldGFsbGVzIHNpIHNhbGUgZGUgbGEgbXVlc3RyYSBjb21vIG9ic2VydmFjacOzbiBpbmZsdXllbnRlLiANCg0KIyDCv0N1w6FsIGVzIGVsIG1lam9yIG1vZGVsbz8NCg0KQ29tbyBkaWNlIGVsICoqUHJpbmNpcGlvIGRlIGxhIE5hdmFqYSBkZSBPY2toYW0qKiwgYSBtZW51ZG8gbGEgZXhwbGljYWNpw7NuIG3DoXMgc2ltcGxlIGVzIGxhIGNvcnJlY3RhLiBRdWVyZW1vcyBzZWxlY2Npb25hciBwcmVkaWN0b3JlcyBxdWUgZXhwbGljYW4gbG9zIGRhdG9zIGRlIGxhIG1hbmVyYSBtw6FzIHNpbXBsZSBwb3NpYmxlLCBzaW4gZGlzbWludWlyIGxhIGNhbGlkYWQgZGUgbGFzIHByZWRpY2Npb25lcyBtdWNoby4NCg0KIyMjIFNlcGFyYWNpb24gZGVsIGRhdGFzZXQgZW4gY29uanVudG9zIGRlIGVudHJlbmFtaWVudG8geSB0ZXN0ICg3MC0zMCUpICANCg0KSGVtb3MgZXNjb2dpZG8gZGlzdGludGFzIHNlbWlsbGFzIHBhcmEgZXN0YXIgZW4gY29uZGljaW9uZXMgZGUgcmVhbGl6YXIgdW4gZXN0dWRpbyBtw6FzIGFtcGxpbywgZW4gbGEgZWxlY2Npw7NuIGRlIGxhcyBtaXNtYXMgc2UgaGEgaW50ZW50YWRvDQpldml0YXIgYXF1ZWxsYXMgcXVlIGdlbmVyYWJhbiBtdWVzdHJhcyBkZW1hc2lhZG8gc2ltaWxhcmVzLiBMYXMgc2VtaWxsYXMgdXNhZGFzIHNvbiAxLCAxMTAwIHkgNSBwb3N0ZXJpb3JtZW50ZSBzZSBpbnRyb2R1Y2lyw6FuIGRvcyBtw6FzIHBhcmEgYWZpbmFyIGVuIGVsIGPDoWxjdWxvIGRlIGVycm9yZXMuDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpzZXQuc2VlZCgxKSANCnRyYWluLjEgPC0gc2FtcGxlKGMoVFJVRSwgRkFMU0UpLCBzaXplID0gbnJvdyhjaGVkZGFyKSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSBjKDAuNywgMC4zKSkNCnRlc3QuMSA8LSAoIXRyYWluLjEpDQpzdW0odGVzdC4xKQ0KbW9kZWwuYWxsMSA8LSBsbSh0YXN0ZSB+IC4sIGRhdGEgPSBjaGVkZGFyW3RyYWluLjEsXSkNCnNldC5zZWVkKDExMDApIA0KdHJhaW4uMiA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIHNpemUgPSBucm93KGNoZWRkYXIpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQ0KdGVzdC4yIDwtICghdHJhaW4uMikNCnN1bSh0ZXN0LjIpDQpzdW0odGVzdC4xPT1UUlVFICYgdGVzdC4yPT1UUlVFKSNzb2xvIDEgcHJlc2VndWltb3MNCm1vZGVsLmFsbDIgPC0gbG0odGFzdGUgfiAuLCBkYXRhID0gY2hlZGRhclt0cmFpbi4yLF0pDQpzZXQuc2VlZCg1KSANCnRyYWluLjMgPC0gc2FtcGxlKGMoVFJVRSwgRkFMU0UpLCBzaXplID0gbnJvdyhjaGVkZGFyKSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSBjKDAuNywgMC4zKSkNCnRlc3QuMyA8LSAoIXRyYWluLjMpDQpzdW0odGVzdC4zKQ0Kc3VtKHRlc3QuMT09VFJVRSAmIHRlc3QuMz09VFJVRSkNCnN1bSh0ZXN0LjI9PVRSVUUgJiB0ZXN0LjM9PVRSVUUpDQptb2RlbC5hbGwzIDwtIGxtKHRhc3RlIH4gLiwgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMyxdKQ0KYGBgDQpDb25zaWRlcmVtb3MgbG9zIGNvbmp1bnRvcyBkZSBlbnRyZW5hbWllbnRvIHJlc3VsdGFudGVzIGRlIGxhcyBzZW1pbGxhczogKnRyYWluLjEqKHNlbWlsbGEgMSksICp0cmFpbi4yKihzZW1pbGxhIDExMDApLCAqdHJhaW4uMyooc2VtaWxsYSA1KS5WZWFhbW9zIHF1ZSBtb2RlbG9zIGRlYmVtb3MgY29uc2lkZXJhciBlbiBiYXNlIGEgbnVlc3Ryb3MgdHJhaW4uDQoNCiMjIyBNw6l0b2RvIEJhY2t3YXJkDQoNClBhcnRpbW9zIGRlbCBtb2RlbG8gY29tcGxldG8gZXN0dWRpYWRvIGVuIGxhIHNlY2Npw7NuIGFudGVyaW9yLCBlc28gc8OtLCBldmFsdWFkbyBlbiBudWVzdHJvcyByZXNwZWN0aXZvcyB0cmFpbiB5IGFwbGljYW1vcyBjb24gJFxhbHBoYSQgPSAwLjA1LCBlbCBtw6l0b2RvIGRlIEJhY2t3YXJkLCBxdWUgY29uc2lzdGUgZW4gZWxpbWluYXIgbGEgdmFyaWFibGUgcXVlICptZW5vcyBpbmZsdXlhKiBhIGxhIHByZWRpY2Npw7NuLiBQcmltZXJvIHJlYWxpemFtb3MgdW5hIGl0ZXJhY2nDs24gZXhwbMOtY2l0YSBkZWwgbcOpdG9kbyBzb2JyZSBsYSBwcmltZXJhIHNlbWlsbGEsIHkgcG9zdGVyaW9ybWVudGUgc2UgY29uc3RydXllbiBhIHRyYXbDqXMgZGUgIGxhIGxpYnJlcmlhICptaXhsbSogZGUgUi4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIHJlbmRlcj1sZW1vbl9wcmludH0NCiMgZHJvcDEobW9kZWwuYWxsLmxtLCB0ZXN0ID0gIkYiKVtbNl1dDQpmaWxhX3B2YWxvcmVzIDwtIGMoMC4zMzYyNywgMC4wNDMxOCwgMC4wMjM2NSApDQpkZl9wdmFsX2Ryb3BfcDEgPC0gZGF0YS5mcmFtZSgiMSIgPSAxLCAiMiIgPSAyLCIzIiA9IDMsIHJvdy5uYW1lcyA9ICJwLXZhbG9yIikNCmNvbG5hbWVzKGRmX3B2YWxfZHJvcF9wMSkgPC0gYygiQWNldGljIiwiSDJTIiwiTGFjdGljIikNCmRmX3B2YWxfZHJvcF9wMVsxLF0gPC0gZmlsYV9wdmFsb3Jlcw0KZGZfcHZhbF9kcm9wX3AxDQpgYGANCg0KRWxpbWluYW1vcyBBY2V0aWMgZGVsIG1vZGVsbyBkZWJpZG8gcXVlIHN1IHAtdmFsb3IgZXMgPjAuMDUuICANCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KbW9kZWwuYmFja3dhcmQgPC0gdXBkYXRlKG1vZGVsLmFsbC5sbSwgLiB+IC4gLSBBY2V0aWMpDQojIGRyb3AxKG1vZGVsLmJhY2t3YXJkLCB0ZXN0ID0gIkYiKVtbNl1dDQpmaWxhX3B2YWxvcmVzIDwtIGMoMC4wNTEyMiAsIDAuMDMyNzUpDQpkZl9wdmFsX2Ryb3BfcDIgPC0gZGF0YS5mcmFtZSgiMSIgPSAxLCAiMiIgPSAyLCByb3cubmFtZXMgPSAicC12YWxvciIpDQpjb2xuYW1lcyhkZl9wdmFsX2Ryb3BfcDIpIDwtIGMoIkgyUyIsIkxhY3RpYyIpDQpkZl9wdmFsX2Ryb3BfcDJbMSxdIDwtIGZpbGFfcHZhbG9yZXMNCmRmX3B2YWxfZHJvcF9wMg0KYGBgDQpSZXBldGltb3MgZWwgcHJvY2VzbyBjb24gbGEgdmFyaWFibGUgSDJTLCB5YSBxdWUgdGllbmUgdW4gcC12YWxvciBtYXlvciBxdWUgJFxhbHBoYSA9IDAuMDUkDQoNCmBgYHtyIGVjaG89RkFMU0UsIHJlbmRlcj1sZW1vbl9wcmludH0NCm1vZGVsLmJhY2t3YXJkIDwtIHVwZGF0ZShtb2RlbC5iYWNrd2FyZCwgLiB+IC4gLSBIMlMpDQojZHJvcDEobW9kZWwuYmFja3dhcmQsIHRlc3QgPSAiRiIpDQpmaWxhX3B2YWxvcmVzIDwtIGMoMS4zODhlLTA1KQ0KZGZfcHZhbF9kcm9wX3AzIDwtIGRhdGEuZnJhbWUoIjEiID0gMSwgcm93Lm5hbWVzID0gInAtdmFsb3IiKQ0KY29sbmFtZXMoZGZfcHZhbF9kcm9wX3AzKSA8LSBjKCJMYWN0aWMiKQ0KZGZfcHZhbF9kcm9wX3AzWzEsXSA8LSBmaWxhX3B2YWxvcmVzDQpkZl9wdmFsX2Ryb3BfcDMNCmBgYA0KDQpFbCBwLXZhbG9yIGVzIG1lbm9yIHF1ZSAkXGFscGhhID0gMC4wNSQsIHBvciBsbyBxdWUgaGVtb3MgY29uY2x1aWRvLCB5YSBxdWUgbm8gdGVuZW1vcyBzdWZpY2llbnRlIGNlcnRlemEgcGFyYSBwb2RlciBlbGltaW5hciBvdHJhIHZhcmlhYmxlLlBvciB0YW50bywgdGVuZW1vcyBjb21vIHJlc3VsdGFkbyBxdWUgbGEgdmFyaWFibGUgcXVlIG1lam9yIGV4cGxpY2EgZWwgKnRhc3RlKiBlcyAqTGFjdGljKi4gTW9kZWxvIHJlc3VsdGFudGU6ICoqdGFzdGUgIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0qKi4gIA0KDQpQb3Igb3RybyBsYWRvIGxvcyBtb2RlbG9zIGJhY2t3YXJkIHJlc3VsdGFudGVzIHBvciAqbWl4bG0qIHNvbjogIA0KDQoqKnRhc3RlICB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMixdKiogeSBwb3Igb3RybyBsYWRvICoqdGFzdGUgIH4gSDJTICsgTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4zLF0qKi4NCg0KIyMjIE3DqXRvZG8gRm9yd2FyZCANCg0KRWwgbcOpdG9kbyBGb3J3YXJkIGNvbnNpc3RlIGVuIGVtcGV6YXIgY29uIHVuIG1vZGVsbyBkZSB1bmEgdmFyaWFibGUgeSB2YW1vcyBhw7FhZGllbmRvIGxhcyBxdWUgbcOhcyBpbmZsdXlhbiwgZGVzYXJyb2xsYXJlbW9zIGVsIHByaW1lciBtb2RlbG8gZGUgZm9ybWEgZXhwbMOtY2l0YSB5IGVsIHJlc3RvIGxvcyBnZW5lcmFyZW1vcyBjb24gKm1peGxtKi4gIERlIGVzdGEgbWFuZXJhIHRlbmVtb3M6ICANCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KU0NPUEU8LSh+LitBY2V0aWMgKyBIMlMgKyBMYWN0aWMpDQptb2RlbC5mb3J3YXJkLmxtIDwtIGxtKHRhc3RlfjEsZGF0YT0gY2hlZGRhclt0cmFpbixdKQ0KI2FkZDEobW9kZWwuZm9yd2FyZC5sbSxzY29wZT1TQ09QRSx0ZXN0PSJGIilbWzZdXQ0KZmlsYV9wdmFsb3JlcyA8LSBjKDEuMjUxNzg2ZS0wMiwgMi4xMTU0NzNlLTA1LCAxLjM4NzkyM2UtMDUpDQpkZl9wdmFsX2Ryb3BfcDEgPC0gZGF0YS5mcmFtZSgiMSIgPSAxLCAiMiIgPSAyLCIzIiA9IDMsIHJvdy5uYW1lcyA9ICJwLXZhbG9yIikNCmNvbG5hbWVzKGRmX3B2YWxfZHJvcF9wMSkgPC0gYygiQWNldGljIiwiSDJTIiwiTGFjdGljIikNCmRmX3B2YWxfZHJvcF9wMVsxLF0gPC0gZmlsYV9wdmFsb3Jlcw0KZGZfcHZhbF9kcm9wX3AxDQpgYGANCkFjdHVhbGl6YW1vcyBhw7FhZGllbmRvIExhY3RpYyBwb3IgdGVuZXIgZWwgbWVub3IgcC12YWxvci4NCmBgYHtyIGVjaG89RkFMU0UsIHJlbmRlcj1sZW1vbl9wcmludH0NCm1vZGVsLmZvcndhcmQubG0gPC0gdXBkYXRlKG1vZGVsLmZvcndhcmQubG0sIC5+LiArIExhY3RpYykNCiMgYWRkMShtb2RlbC5mb3J3YXJkLmxtLHNjb3BlPVNDT1BFLHRlc3Q9IkYiKVtbNl1dDQpmaWxhX3B2YWxvcmVzIDwtIGMoMC41MDM5ODc3NCAsMC4wNTEyMTcxMTUpDQpkZl9wdmFsX2Ryb3BfcDEgPC0gZGF0YS5mcmFtZSgiMSIgPSAxLCAiMiIgPSAyLCByb3cubmFtZXMgPSAicC12YWxvciIpDQpjb2xuYW1lcyhkZl9wdmFsX2Ryb3BfcDEpIDwtIGMoIkFjZXRpYyIsIkgyUyIpDQpkZl9wdmFsX2Ryb3BfcDFbMSxdIDwtIGZpbGFfcHZhbG9yZXMNCmRmX3B2YWxfZHJvcF9wMQ0KYGBgDQpDb24gbml2ZWwgZGUgc2lnbmlmaWNhY2nDs24gJFxhbHBoYSQgPSAwLjA1IGVzdGUgc2Vyw61hIG51ZXN0cm8gbW9kZWxvIGZpbmFsLiBNb2RlbG8gcmVzdWx0YW50ZSA9ICoqdGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjEsXSoqICANClBvciBvdHJvIGxhZG8gbG9zIG1vZGVsb3MgZm9yd2FyZCByZXN1bHRhbnRlcyBwb3IgKm1peGxtKiBzb246ICANCg0KKip0YXN0ZSAgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjIsXSoqIHkgcG9yIG90cm8gbGFkbyAqKnRhc3RlICB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMyxdKiouDQoNCiMjIENvbnN0cnVjY2nDs24gcG9yIGNyaXRlcmlvcw0KDQpFbiBlc3RhIHN1YnNlY2Npw7NuIHRyYXRhcmVtb3MgZGUgZW5jb250cmFyIHVuIGNhbmRpZGF0byBhIG1lam9yIG1vZGVsbywgY29uc3RydXllbmRvIG51ZXN0cm9zIG1vZGVsb3MgdXNhbmRvIGRpc3RpbnRvcyBlbmZvcXVlcy4gVHJhcyBhcGxpY2FyDQpsb3Mgc2lndWllbnRlcyBjcml0ZXJpb3MgYSBsYSBob3JhIGRlbCBkZXNhcnJvbGxvIGRlIG1vZGVsb3M6ICRSXjIkIGFqdXN0YWRvLCBDcCBkZSBNYWxsb3dzLCBDcml0ZXJpbyBkZSBJbmZvcm1hY2lvbiBkZSBCYXllcyAoQklDKSwgQ3JpdGVyaW8gZGUgSW5mb3JtYWNpb24gZGUgQWthaWtlIChBSUMpIGVsaWdpZW5kbyBlbCBxdWUgbm9zIGRlIHVuIG1lbm9yIG8gbWF5b3IgY29lZmljaWVudGUgc2Vnw7puIGVsIG3DqXRvZG8gKGxvcyBkZXNhcnJvbG9zIHNlIHB1ZWRlbiBlbmNvbnRyYXIgZW4gZWwgc2NyaXB0KSwgbGxlZ2Ftb3MgYSBsYXMgc2lndWllbnRlcyBjb25jbHVzaW9uZXM6ICANCnNvbG8gYXBhcmVjZSB1biBtb2RlbG8gbnVldm8gdXNhbmRvIGVsIGNyaXRlcmlvIGRlbCBlc3RhZMOtc3RpY28gJFJeMiQgcGFyYSBsYSBwcmltZXJhIHNlbWlsbGEsICoqdGFzdGUgIH4gSDJTICsgTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0qKi4gIA0KTm90YW1vcyBxdWUgbGEgY29tYmluYWNpw7NuIGRlIEgyUyArIEwgYXBhcmVjZSBlbiB0b2RvcyBudWVzdHJvcyBjb25qdW50b3MgZGUgZW50cmVuYW1pZW50byBlbiBhbGfDum4gbW9tZW50bywgZXMgY2FuZGlkYXRhIGEgc2VyIG51ZXN0cmEgbWVqb3IgZWxlY2Npw7NuLiAgDQoNCkNvbXBhcmFtb3MgbG9zIG1vZGVsb3Mgb2J0ZW5pZG9zIGhhc3RhIGFob3JhIGVuIHN1IHJlc3BlY3RpdmEgbXVlc3RyYSBkZSBlbnRyZW5hbWllbnRvIGNvbiBlbCBtb2RlbG8gY29tcGxldG8gZW4gZXNlIGNvbmp1bnRvIGRlIGVudHJlbmFtaWVudG8uDQoNCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KbW9kZWwuMSA8LSBsbSh0YXN0ZSB+IExhY3RpYywgIGRhdGE9Y2hlZGRhclt0cmFpbi4xLF0pDQptb2RlbC4xY3JpdCA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YT1jaGVkZGFyW3RyYWluLjEsXSkNCm1vZGVsLjIgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsICBkYXRhPWNoZWRkYXJbdHJhaW4uMixdKQ0KbW9kZWwuMyA8LSBsbSh0YXN0ZSB+IEgyUyArTGFjdGljLCAgZGF0YT1jaGVkZGFyW3RyYWluLjMsXSkNCiMgYW5vdmEobW9kZWwuMSxtb2RlbC5hbGwxKVtbNl1dDQojIGFub3ZhKG1vZGVsLjFjcml0LG1vZGVsLmFsbDEpW1s2XV0NCiMgYW5vdmEobW9kZWwuMixtb2RlbC5hbGwyKQ0KIyBhbm92YShtb2RlbC4zLG1vZGVsLmFsbDMpW1s2XV0NCmZpbGFfcHZhbG9yZXMgPC0gYygwLjA5ODIxNDUzLA0KICAgICAgICAgICAgICAgICAgIDAuMzM2MjY4OSwNCiAgICAgICAgICAgICAgICAgICAwLjk1NTExMjMsDQogICAgICAgICAgICAgICAgICAgMC41NTUxMjkyKQ0KYW5vdmEobW9kZWwuMSxtb2RlbC5hbGwxKSAgICAgICAgICAgICAgICANCmRmX3B2YWxfZHJvcF9wMSA8LSBkYXRhLmZyYW1lKCIxIiA9IDEsICIyIiA9IDIsIjMiID0gMywiNCI9IDQsIHJvdy5uYW1lcyA9ICJwLXZhbG9yIikNCmNvbG5hbWVzKGRmX3B2YWxfZHJvcF9wMSkgPC0gYygidHJhaW4xOiBMIHZzIENvbXBsZXRvIiwidHJhaW4xOiBIMlMgKyBMIHZzIENvbXBsZXRvIiwidHJhaW4yOiBIMlMgKyBMIHZzIENvbXBsZXRvIiwgInRyYWluMTogSDJTKyBMIHZzIENvbXBsZXRvIikNCmRmX3B2YWxfZHJvcF9wMVsxLF0gPC0gZmlsYV9wdmFsb3Jlcw0KZGZfcHZhbF9kcm9wX3AxICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgIA0KYGBgDQoNCkNvbiBlc3RvcyBwLXZhbG9yZXMgcG9kZW1vcyBkZWNpciBxdWUgY29uIHVuIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuICRcYWxwaGEkIG5pbmfDum4gbW9kZWxvIGVzIG5vdGFibGVtZW50ZSBkaWZlcmVudGUgZGUgc3UgY29udHJhcGFydGUgc2Fsdm8gZW4gZWwgY2FzbyBkZSBsb3MgbW9kZWxvcyByZXN1bHRhbnRlcyBlbiAqdHJhaW4yKiBlc3RvIHB1ZWRlIHNlciBwb3IgbGEgY2FudGlkYWQgZGUgb2JzZXJ2YWNpb25lcyBpbmZsdXllbnRlcyBwcmVzZW50ZXMgZW4gbGEgbXVlc3RyYSwgbG8gdHJhdGFyZW1vcyBlbiBsYSBzaWd1aWVudGUgc2VjY2nDs24uICANCg0KIyBEaWFnbm9zdGljbzogQ29tcHJvYmFjaW9uZXMgZGUgaGlwb3Rlc2lzLCBvdXRsaWVycyB5IG9ic2VydmFjaW9uZXMgaW5mbHV5ZW50ZXMNCg0KRW4gZXN0YSBzZWNjacOzbiBlc3R1ZGlhcmVtb3Mgc2kgbnVlc3Ryb3MgbW9kZWxvcyBjdW1wbGVuIGxhcyBjb25kaWNpb25lcw0KbmVjZXNhcmlhcyBkZSB1biBtb2RlbG8gZGUgcmVncmVzacOzbiBsaW5lYWwuICANCg0KTnVlc3RybyBlbmZvcXVlIGNvbnNpc3RpcsOhIGVuIHVuIGFuw6FsaXNpcyBncsOhZmljbywgYWNvbXBhw7FhZG8gZGUgdGVzdHMNCmVzdGFkw61zdGljb3MgZW4gbG9zIGNhc29zIGVuIGxvcyBxdWUgc2UgYXByZWNpZSB1bmEgZGlzY3JlcGFuY2lhIG5vdGFibGUuDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQphdHRhY2goY2hlZGRhcikNCmBgYA0KDQojIyDCv1NvbiBudWVzdHJvcyAqbW9kZWxvcyosIG1vZGVsb3MgZGUgcmVncmVzacOzbiBsaW5lYWw/OiBDb21wcm9iYWNpw7NuIGRlIGhpcMOzdGVzaXMuDQoNCkVuIGxhIHNlY2Npw7NuIDMgc2UgdG9tYSB1biBlbmZvcXVlICpuYcOvdmUqIGEgbGEgaG9yYSBkZSBjb25zdHJ1aXIgbG9zIG1vZGVsb3MsDQp5YSBxdWUgbm8gaGVtb3MgZXN0dWRpYWRvIHNpIGhheSBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzLCBwb2Ryw61hbW9zIHRlbmVyIHVuYQ0KbXVlc3RyYSBxdWUgbm8gZXMgbGEgYWRlY3VhZGEgcGFyYSBlbCBlc3R1ZGlvIGRlIG51ZXN0cm9zIGRhdG9zLiAgDQoNClVuIG1vZGVsbyBkZSByZWdyZXNpw7NuIGxpbmVhbCBkZWJlIHNhdGlzZmFjZXIgbGFzIHNpZ3VpZW50ZXMgaGlww7N0ZXNpcyBjb24gbml2ZWwgDQpkZSBzaWduaWZpY2FjacOzbiAkXGFscGhhJCBhZGVjdWFkbzoNCg0KMS4gTG9zIGVycm9yZXMgXChcZXBzaWxvbl97aX1cKSB0aWVuZW4gZGlzdHJpYnVjacOzbiBub3JtYWwuICANCjIuIExvcyBlcnJvcmVzIFwoXGVwc2lsb25fe2l9XCkgdGllbmVuIG1lZGlhIGNlcm8uICANCjMuIExvcyBlcnJvcmVzIFwoXGVwc2lsb25fe2l9XCkgdGllbmVuIHZhcmlhbnphIGNvbnN0YW50ZS4gIA0KNC4gTG9zIGVycm9yZXMgXChcZXBzaWxvbl97aX1cKSBubyBlc3TDoW4gY29ycmVsYWNpb25hZG9zLiAgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0UsIHJlbmRlcj1sZW1vbl9wcmludH0NCmFsZmFuIDwtIDAuMDUNCmZpbGFfbGluZWFsaWRhZCA8LSBjKHJvdW5kKHJlc2V0dGVzdChtb2RlbC4xLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4xLF0pJHAudmFsdWUsMyksDQogICAgICAgICAgICAgICAgICAgICByb3VuZChyZXNldHRlc3QobW9kZWwuMWNyaXQsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjEsXSkkcC52YWx1ZSwzKSwNCiAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHJlc2V0dGVzdChtb2RlbC4yLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4yLF0pJHAudmFsdWUsMyksDQogICAgICAgICAgICAgICAgICAgICByb3VuZChyZXNldHRlc3QobW9kZWwuMywgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMyxdKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgYWxmYW4sIlJlc2V0dGVzdCIpDQpmaWxhX25vcm1hbGlkYWQgPC0gYyhyb3VuZChzaGFwaXJvLnRlc3QocmVzaWQobW9kZWwuMSkpJHAudmFsdWUsMyksDQogICAgICAgICAgICAgICAgICAgICByb3VuZChzaGFwaXJvLnRlc3QocmVzaWQobW9kZWwuMWNyaXQpKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjIpKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjMpKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgYWxmYW4sICJUZXN0IFNoYXBpcm8gV2lsayIpDQpmaWxhX21lZGlhTyA8LSBjKHQudGVzdChyZXNpZChtb2RlbC4xKSwgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSRwLnZhbHVlLA0KICAgICAgICAgICAgICAgICB0LnRlc3QocmVzaWQobW9kZWwuMWNyaXQpLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpJHAudmFsdWUsDQogICAgICAgICAgICAgICAgIHQudGVzdChyZXNpZChtb2RlbC4yKSwgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSRwLnZhbHVlLA0KICAgICAgICAgICAgICAgICB0LnRlc3QocmVzaWQobW9kZWwuMyksIG11ID0gMCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikkcC52YWx1ZSwNCiAgICAgICAgICAgICAgICAgYWxmYW4sICJ0LXRlc3QiKQ0KZmlsYV92YXJfY3RlIDwtIGMocm91bmQobmN2VGVzdChtb2RlbC4xKSRwLDMpLA0KICAgICAgICAgICAgICAgICAgcm91bmQobmN2VGVzdChtb2RlbC4xY3JpdCkkcCwzKSwNCiAgICAgICAgICAgICAgICAgIHJvdW5kKG5jdlRlc3QobW9kZWwuMikkcCwzKSwNCiAgICAgICAgICAgICAgICAgIHJvdW5kKG5jdlRlc3QobW9kZWwuMykkcCwzKSwNCiAgICAgICAgICAgICAgICAgIGFsZmFuLCAiVGVzdCBuY3YiKQ0KICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICANCmZpbGFfY29yciA8LSBjKGR1cmJpbldhdHNvblRlc3QobW9kZWwuMSkkcCwNCiAgICAgICAgICAgICAgIGR1cmJpbldhdHNvblRlc3QobW9kZWwuMWNyaXQpJHAsDQogICAgICAgICAgICAgICBkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjIpJHAsDQogICAgICAgICAgICAgICBkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjMpJHAsDQogICAgICAgICAgICAgICBhbGZhbiwiVGVzdCBkZSBEdXJiaW4tV2F0c29uIikNCiANCmRmX3B2YWxfZHJvcF9wMSA8LSBkYXRhLmZyYW1lKCIxIiA9IHJlcCgwLDUpLCIyIiA9IHJlcCgwLDUpLCIzIiA9IHJlcCgwLDUpLCI0Ij0gcmVwKDAsNSksICI1Ij0gcmVwKDAsNSksICI2IiA9IHJlcCgwLDUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPWMoIkxpbmVhbGlkYWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcm1hbGlkYWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGlhID0gMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmFyaWFuemEgY29uc3RhbnRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JyZWxhY2nDs24iKSkNCmNvbG5hbWVzKGRmX3B2YWxfZHJvcF9wMSkgPC0gICAgYygidHJhaW4xOiBMIiwidHJhaW4xOiBIMlMgKyBMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidHJhaW4yOiBIMlMgKyBMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidHJhaW4zOiBIMlMgKyBMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTml2ZWwgZGUgc2lnaW5pZmljYWNpw7NuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVzdCB1dGlsaXphZG8iKQ0KDQpkZl9wdmFsX2Ryb3BfcDFbMSxdIDwtIGZpbGFfbGluZWFsaWRhZA0KZGZfcHZhbF9kcm9wX3AxWzIsXSA8LSBmaWxhX25vcm1hbGlkYWQNCmRmX3B2YWxfZHJvcF9wMVszLF0gPC0gZmlsYV9tZWRpYU8NCmRmX3B2YWxfZHJvcF9wMVs0LF0gPC0gZmlsYV92YXJfY3RlDQpkZl9wdmFsX2Ryb3BfcDFbNSxdIDwtIGZpbGFfY29ycg0KYGBgDQoNCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KZGZfcHZhbF9kcm9wX3AxDQpgYGANCg0KDQpQb2RlbW9zIG9ic2VydmFyIHF1ZSBzZSB2ZXJpZmljYW4gYSBuaXZlbCBkZSBzaWduaWZpY2FjacOzbiAkXGFscGhhJCA9IDAuMDUgc2UgdmVyaWZpY2FuIHRvZGFzIGxhcyBoaXDDs3Rlc2lzIGRlIG1vZGVsbyBkZSByZWdyZXNpw7NuIGxpbmVhbC4gRW4gbGFzIHNpZ3VpZW50ZXMgZ3LDoWZpY2FzIHBvZGVtb3Mgb2JzZXJ2YXIgY29tbyBsb3MgcmVzaWR1b3MgZGUgbG9zIG1vZGVsb3MgKip0YXN0ZSB+IEgyUyArIEwqKiBkZSBsb3MgY29uanVudG9zICp0cmFpbjIqIHkgKnRyYWluMyogc2UgY29tcG9ydGFuIG1lam9yIHF1ZSBjdWFscXVpZXJhIGRlIGxvcyBtb2RlbG9zIHByb3B1ZXN0b3MgZW4gbGEgbXVlc3RyYSAqdHJhaW4xKg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD02fQ0KcGFyKG1mcm93PWMoMSwyKSkNCnFxbm9ybShyZXNpZChtb2RlbC4xKSkNCnFxbGluZShyZXNpZChtb2RlbC4xKSkNCg0KcXFub3JtKHJlc2lkKG1vZGVsLjFjcml0KSkNCnFxbGluZShyZXNpZChtb2RlbC4xY3JpdCkpDQoNCmBgYA0KYGBge3IgZWNobz1GQUxTRSwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9Nn0NCnBhcihtZnJvdz1jKDEsMikpDQpxcW5vcm0ocmVzaWQobW9kZWwuMikpDQpxcWxpbmUocmVzaWQobW9kZWwuMikpDQoNCnFxbm9ybShyZXNpZChtb2RlbC4zKSkNCnFxbGluZShyZXNpZChtb2RlbC4zKSkNCg0KYGBgDQoNCg0KUG9zdGVyaW9ybWVudGUsIHJlYWxpemFtb3MgdW4gZXN0dWRpbyBkZSBsYSBjb2xpbmVhbGlkYWQuIFBhcmEgZWxsbywgb2JzZXJ2YW1vcyBxdWUgZWwgbW9kZWxvICoqdGFzdGUgfiBMYWN0aWMgLCBkYXRhPWNoZWRkYXJbdHJhaW4uMSxdKiogc29sbyB0aWVuZSB1biBwcmVkaWN0b3IgbHVlZ28gbm8gaGF5IHByZXNlbnRlIG5pbmfDum4gdGlwbyBjb2xpbmVhbGlkYWQuDQoNCmBgYHtyIGVjaG89RkFMU0UsIHJlbmRlcj1sZW1vbl9wcmludH0NCiMgdmlmKG1vZGVsLjEpIGRpamltb3MgcXVlIGVsIGRlIGxhY3RpYyBubyBwb3JxdWUgc3VjZWRlIGVzdG8gbm8gaGF5IGNvbGluIHBvciBzb2xvIDEgdmFyDQojIHZpZihtb2RlbC4xY3JpdCkNCiMgdmlmKG1vZGVsLjIpDQojIHZpZihtb2RlbC4zKSAjIGxvcyB2YWxvcmVzIGRlIFZJRiBubyBpbmRpY2FuIGNvbGluZWFsaWRhZCBncmF2ZQ0KDQoNCmRmX3B2YWxfZHJvcF9wMSA8LSBkYXRhLmZyYW1lKCIxIiA9IHJlcCgwLDQpLCIyIiA9IHJlcCgwLDQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID1jKCJ0cmFpbjE6IEwiLCJ0cmFpbjE6IEgyUyArIEwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0cmFpbjI6IEgyUyArIEwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0cmFpbjM6IEgyUyArIEwiKSkNCg0KZmlsYV9jMSA8LSBjKCJTb2xvIHRpZW5lIHVuIHByZWRpY3RvciIsIlNvbG8gdGllbmUgdW4gcHJlZGljdG9yIikNCmZpbGFfYzIgPC0gYyh2aWYobW9kZWwuMWNyaXQpW1sxXV0sdmlmKG1vZGVsLjFjcml0KVtbMl1dKQ0KZmlsYV9jMyA8LSBjKHZpZihtb2RlbC4yKVtbMV1dLHZpZihtb2RlbC4yKVtbMl1dKQ0KZmlsYV9jNCA8LSBjKHZpZihtb2RlbC4zKVtbMV1dLHZpZihtb2RlbC4zKVtbMl1dKQ0KDQpkZl9wdmFsX2Ryb3BfcDFbMSxdIDwtIGZpbGFfYzENCmRmX3B2YWxfZHJvcF9wMVsyLF0gPC0gZmlsYV9jMg0KZGZfcHZhbF9kcm9wX3AxWzMsXSA8LSBmaWxhX2MzDQpkZl9wdmFsX2Ryb3BfcDFbNCxdIDwtIGZpbGFfYzQNCg0KY29sbmFtZXMoZGZfcHZhbF9kcm9wX3AxKSA8LSBjKCJIMlMiLCJMYWN0aWMiKQ0KZGZfcHZhbF9kcm9wX3AxDQoNCmBgYA0KDQpOdWVzdHJvcyB2YWxvcmVzIHNvbiBtdXkgYnVlbm9zLCBlbnRlbmRpZW5kbyBwb3IgYnVlbm8gVklGIDwgMTAsIHBvciBsbyB0YW50byBubyB0ZW5lbmVtb3MgcXVlIHByZW9jdXBhcm5vcyBkZSB1bmEgY29saW5lYWxpZGFkIGdyYXZlIGVudHJlIGxhcyB2YXJpYWJsZXMuDQoNCg0KIyMgRXN0dWRpbyBkZSBvdXRsaWVycw0KDQpBIGZpbiBkZSBvYnRlbmVyIGRpc3RpbnRvcyBwdW50b3MgZGUgdmlzdGEgdXRpbGl6YXJlbW9zIGRvcyBtw6l0b2RvcywgdW4gdmFsb3IgZGUgQm9uZmVycm9uaSBlbiB1biBlc3RhZMOtc3RpY28gJHRfezEtXGZyYWN7XGFscGhhfXsybn07bi1wLTF9JCB5IGxhIGZ1bmNpw7NuICpvdXRsaWVyVGVzdCogcXVlIHV0aWxpemEgcC12YWxvcmVzIGRlIEJvbmZlcnJvbmkgb2J0ZW5pZG9zIGEgdHJhdsOpcyBkZSB0LXRlc3RzLiAgDQoNCkVuIGxvcyBjdWF0cm8gbW9kZWxvcyB5IGJham8gbG9zIGRvcyBjcml0ZXJpb3Mgbm8gc2Ugb2J0aWVuZSBuaW5ndW5hIG9ic2VydmFjacOzbiBxdWUgc2UgcHVlZGEgYWNlcHRhciBjb21vICpvdXRsaWVyKiBhIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuICRcYWxwaGEkID0gMC4wNQ0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0Kc2lnbmkgPC0gMC4wNQ0KDQpuMTwtbnJvdyhjaGVkZGFyW3RyYWluLjEsXSkNCnAxIDwtbnJvdyhzdW1tYXJ5KG1vZGVsLjEpJGNvZWYpDQoNCg0KbjFjcml0PC1ucm93KGNoZWRkYXJbdHJhaW4uMSxdKQ0KcDFjcml0IDwtbnJvdyhzdW1tYXJ5KG1vZGVsLjFjcml0KSRjb2VmKQ0KDQpuMjwtbnJvdyhjaGVkZGFyW3RyYWluLjIsXSkNCnAyIDwtbnJvdyhzdW1tYXJ5KG1vZGVsLjIpJGNvZWYpDQoNCm4zPC1ucm93KGNoZWRkYXJbdHJhaW4uMyxdKQ0KcDMgPC1ucm93KHN1bW1hcnkobW9kZWwuMykkY29lZikNCg0KQkNWMSA8LSBxdCgxIC0gc2lnbmkgLyAoMiAqIG4xKSwgbjEtcDEtMSkgDQpCQ1YxY3JpdCA8LSBxdCgxIC0gc2lnbmkgLyAoMiAqIG4xY3JpdCksIG4xY3JpdC1wMWNyaXQtMSkgDQpCQ1YyIDwtIHF0KDEgLSBzaWduaSAvICgyICogbjIpLCBuMi1wMi0xKSANCkJDVjMgPC0gcXQoMSAtIHNpZ25pIC8gKDIgKiBuMyksIG4zLXAzLTEpIA0KDQpzdW0oYWJzKHJzdHVkZW50KG1vZGVsLjEpKSA+IEJDVjEpDQpzdW0oYWJzKHJzdHVkZW50KG1vZGVsLjFjcml0KSkgPiBCQ1YxY3JpdCkNCnN1bShhYnMocnN0dWRlbnQobW9kZWwuMikpID4gQkNWMikNCnN1bShhYnMocnN0dWRlbnQobW9kZWwuMykpID4gQkNWMykNCg0KDQpvdXRsaWVyVGVzdChtb2RlbC4xKQ0Kb3V0bGllclRlc3QobW9kZWwuMWNyaXQpI05BPw0Kb3V0bGllclRlc3QobW9kZWwuMikgIyBubyBoYXkgZW4gbmluZ3VubyBkZSBsb3MgZG9zIG1vZGVsb3MgcGxhbnRlYWRvcw0Kb3V0bGllclRlc3QobW9kZWwuMykNCg0KYGBgDQojIyBFc3R1ZGlvIGRlIG9ic2VydmFjaW9uZXMgSW5mbHV5ZW50ZXMNCg0KQWwgaWd1YWwgcXVlIGVuIGxhIGFudGVyaW9yIHNlY2Npw7NuIGEgZmluIGRlIHBvZGVyIGVuY29udHJhciBlbCBjcml0ZXJpbyBxdWUgbWVqb3Igc2UgYWp1c3RlIGEgbnVlc3RybyBtb2RlbG8sIGVuIGVsIHF1ZSBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZXMgdW5hIG11ZXN0cmEgZGUgdGFtYcOxbyByZWR1Y2lkbywgdXRpbGl6YXJlbW9zIHZhcmlvcyBjcml0ZXJpb3MsIGFkZW3DoXMgZGUgZGlzdGludGFzIHTDqWNuaWNhcyBncsOhZmljYXMuIExvcyBjcml0ZXJpb3MgdXNhZG9zIHNlcsOhbjogIA0KMS5Dcml0ZXJpbyAxOiB2YWxvcmVzIGxldmVyYWdlIChoaWkpIG1heW9yZXMgcXVlICRcZnJhY3sycH17bn0kLiAgDQoyLkNyaXRlcmlvIDI6IHZhbG9yZXMgfERGRklUU3wgc29uIG1heW9yZXMgcXVlICQyIFxjZG90IFxzcXJ0e1xmcmFjezJwfXtufX0kLiAgDQoNCjMuQ3JpdGVyaW8gMzogdmFsb3JlcyB8REZCRVRBU3wgbWF5b3JlcyBxdWUgJDIgXGNkb3QgXHNxcnR7XGZyYWN7MnB9e259fSQuICANCg0KNC5Dcml0ZXJpbyA0OiAqSW5mbHVlbmNlUGxvdCouDQoNCkVuIGxhIHNpZ3VpZW50ZSB0YWJsYSBvYnNlcnZhbW9zIGxhcyBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzIG9idGVuaWRhcyBwb3IgY2FkYSBjcml0ZXJpby4NCg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KDQpkZl9wdmFsX2Ryb3BfcDEgPC0gZGF0YS5mcmFtZSgiMSIgPSByZXAoMCw0KSwiMiIgPSByZXAoMCw0KSwiMyIgPSByZXAoMCw0KSwiNCIgPSByZXAoMCw0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9YygidHJhaW4xOiBMIiwidHJhaW4xOiBIMlMgKyBMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidHJhaW4yOiBIMlMgKyBMIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidHJhaW4zOiBIMlMgKyBMIikpDQoNCmZpbGFfYzEgPC0gYygiMSw1LDE2LDIzLDI0LDI2IiwgIjEsMTIsMjQiLCIxLDMsNSw4LDksMTIsMTMsMTQsMTYsMTksMjMsMjQsMjcsMjgsMzAiLCIxLDEyLDI0IikNCmZpbGFfYzIgPC0gYygiMjMiLCAiMTIiLCAiMSwzLDgsOSwxMSwxMiwxMywxNCwxOSwyMywyNCwyNiwyNywyOCwzMCIsIjEsOCwxMiwyMyIpDQpmaWxhX2MzIDwtIGMoIjYiLCJOaW5ndW5vIiAsICIxLDMsNCw3LDgsOSwxMSwxMiwxNiwxNywyMCwyOSwzMCIsIjEsNiw3LDgsMTUiKQ0KZmlsYV9jNCA8LSBjKCJOaW5ndW5vIiwiTmluZ3VubyIsIjEsNCw1LDcsMTIsMTQsMTYsMTcsMTksMjMsMjcsMjkiLCIxLDcsMTUsMTksMjQiKQ0KY29sbmFtZXMoZGZfcHZhbF9kcm9wX3AxKSA8LSBjKCJDcml0ZXJpbyAxIiwiQ3JpdGVyaW8gMiIsIkNyaXRlcmlvIDMiLCJDcml0ZXJpbyA0IikNCg0KZGZfcHZhbF9kcm9wX3AxWzEsXSA8LSBmaWxhX2MxDQpkZl9wdmFsX2Ryb3BfcDFbMixdIDwtIGZpbGFfYzINCmRmX3B2YWxfZHJvcF9wMVszLF0gPC0gZmlsYV9jMw0KZGZfcHZhbF9kcm9wX3AxWzQsXSA8LSBmaWxhX2M0DQpkZl9wdmFsX2Ryb3BfcDENCmBgYA0KDQpUb21hbW9zIGxhIGRlY2lzacOzbiBkZSBlbGVnaXIgbG9zIGVsZW1lbnRvcyBxdWUgc2UgcmVwaXRhbiBlbiB2YXJpb3MgeWEgcXVlIHNpIGVsaW1pbsOhc2Vtb3MgbG9zIGRlbCBjcml0ZXJpbyAzIGVsIHJlc3VsdGFkbyBzZXLDrWEgZGVtYXNpYWRvIHBlcXVlw7FvIHBhcmEgc2VyIGFwdG8gcGFyYSBsYSByZWdyZXNpw7NuIGxpbmVhbC4gTnVlc3RybyBjcml0ZXJpbyBhIHNlZ3VpciBlcyBxdWUgZXN0w6luIGVuIGFsIG1lbm9zIGRvcyBjcml0ZXJpb3MgIGRlIGxvcyByZXN0YW50ZXMuDQoNCmBgYHtyIGVjaG89RkFMU0V9DQoNCnBhcihtZnJvdz1jKDIsMikpDQpwMSA8LSBpbmZsdWVuY2VQbG90KG1vZGVsLjEpDQpwb3NfaW5mbHV5ZW50ZXNfMSA8LSBjKDEsMTIsMjQpDQoNCnAyIDwtaW5mbHVlbmNlUGxvdChtb2RlbC4xY3JpdCkNCnBvc19pbmZsdXllbnRlc18xY3JpdCA8LSBjKDEsOCwxMiwyMykNCg0KcDMgPC1pbmZsdWVuY2VQbG90KG1vZGVsLjIpDQpwb3NfaW5mbHV5ZW50ZXNfMiA8LSBjKDEsNiw3LDgsMTUpDQoNCg0KcDQgPC1pbmZsdWVuY2VQbG90KG1vZGVsLjMpDQpwb3NfaW5mbHV5ZW50ZXNfMyA8LSBjKDEsNywxNSwxOSwyNCkNCg0KYGBgDQoNCkVzdGFzIG9ic2VydmFjaW9uZXMgc29uIGxhcyBwcmVzZW50ZXMgZW4gbGEgY3VhcnRhIGNvbHVtbmEgZGUgbGEgdGFibGEgeSBlbiBnZW5lcmFsIHNvbiBlbiBsYXMgcHJpbWVyYXMgZW4gbGFzIHF1ZSBub3MgZmlqZW1vcyBhIGxhIGhvcmEgZGUgdmVyIHNpIGxhcyB0b21hbW9zIGNvbW8gaW5mbHV5ZW50ZXMgbyBuby4NCg0KQmFqbyBudWVzdHJvIGNyaXRlcmlvIHF1ZWRhcsOtYW4gY29tbyBwb3NpYmxlcyBpbmZsdXllbnRlcyBsYXMgc2lndWllbnRlcyBvYnNlcnZhY2lvbmVzOg0KDQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnR9DQpkZl9wdmFsX2Ryb3BfcDEgPC0gZGF0YS5mcmFtZSgiMSIgPXJlcCgwLDQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID1jKCJ0cmFpbjE6IEwiLCJ0cmFpbjE6IEgyUyArIEwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0cmFpbjI6IEgyUyArIEwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0cmFpbjM6IEgyUyArIEwiKSkNCg0KZmlsYV9jMSA8LSBjKCIxLDEyIikNCmZpbGFfYzIgPC0gYygiMSwxMiwyMyIpDQpmaWxhX2MzIDwtIGMoIjIsNiIpDQpmaWxhX2M0IDwtIGMoIk5vIHNlIHJlcGl0ZSBuaW5ndW5vIikNCmNvbG5hbWVzKGRmX3B2YWxfZHJvcF9wMSkgPC0gYygiT2JzZXJ2YWNpb25lcyBpbmZsdXllbnRlcyIpDQoNCmRmX3B2YWxfZHJvcF9wMVsxLF0gPC0gZmlsYV9jMQ0KZGZfcHZhbF9kcm9wX3AxWzIsXSA8LSBmaWxhX2MyDQpkZl9wdmFsX2Ryb3BfcDFbMyxdIDwtIGZpbGFfYzMNCmRmX3B2YWxfZHJvcF9wMVs0LF0gPC0gZmlsYV9jNA0KZGZfcHZhbF9kcm9wX3AxDQpgYGANCg0KDQpBaG9yYSBlcyBjdWFuZG8gdGVuZW1vcyBxdWUgZGV0ZXJtaW5hciBzaSB2YW4gYSBzZXIgaW5mbHV5ZW50ZXMgbyBubywgZXN0byBsbyB2ZXJlbW9zIGNvbXBhcmFuZG8gbG9zIG1vZGVsb3MgY29uIGxhcyBtdWVzdHJhcyBkZSBlbnRyZW5hbWllbnRvIHNpbiBlbGltaW5hciBpbmZsdXllbnRlcyB5IGNvbiBsYXMgbXVlc3RyYXMgbW9kaWZpY2FkYXMsIHkgZXZhbHVhciBzaSBtZWpvcmFuIG8gZW1wZW9yYW4gbG9zIHAtdmFsb3JlcyBkZSBsYXMgaGlww7N0ZXNpcyBkZSBsb3MgbW9kZWxvcyBkZSByZWdyZXNpw7NuLg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KcG9zXzE8LWMoVFJVRSxyZXAoRkFMU0UsMTApLFRSVUUscmVwKEZBTFNFLDE4KSkNCnRyYWluLjFpbmY8LXRyYWluLjEmIXBvc18xDQptb2RlbC4xaW5mPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjFpbmYsXSkNCmBgYA0KIyMjIHRhc3RlIH4gICsgTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0gdnMgdGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjFpbmYsXQ0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KDQpmaWxhX2xpbmVhbGlkYWQgPC0gYyhyb3VuZChyZXNldHRlc3QobW9kZWwuMSwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMSxdKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQocmVzZXR0ZXN0KG1vZGVsLjFpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjFpbmYsXSkkcC52YWx1ZSwzKSwNCiAgICAgICAgICAgICAgICAgICAgICJSZXNldHRlc3QiKQ0KDQoNCmZpbGFfbm9ybWFsaWRhZCA8LSBjKHJvdW5kKHNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xKSkkcC52YWx1ZSwzKSwNCiAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xY3JpdCkpJHAudmFsdWUsMyksDQogICAgICAgICAgICAgICAgICAgICAiVGVzdCBTaGFwaXJvIFdpbGsiKQ0KZmlsYV9tZWRpYU8gPC0gYyh0LnRlc3QocmVzaWQobW9kZWwuMSksIG11ID0gMCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikkcC52YWx1ZSwNCiAgICAgICAgICAgICAgICAgdC50ZXN0KHJlc2lkKG1vZGVsLjFpbmYpLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpJHAudmFsdWUsDQogICAgICAgICAgICAgICAgICJ0LXRlc3QiKQ0KZmlsYV92YXJfY3RlIDwtIGMocm91bmQobmN2VGVzdChtb2RlbC4xKSRwLDMpLA0KICAgICAgICAgICAgICAgICAgcm91bmQobmN2VGVzdChtb2RlbC4xaW5mKSRwLDMpLA0KICAgICAgICAgICAgICAgICAgIlRlc3QgbmN2IikNCiAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgDQpmaWxhX2NvcnIgPC0gYyhkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjEpJHAsDQogICAgICAgICAgICAgICBkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjFpbmYpJHAsDQogICAgICAgICAgICAgICAiVGVzdCBkZSBEdXJiaW4tV2F0c29uIikNCiANCmRmX3B2YWxfZHJvcF9wMSA8LSBkYXRhLmZyYW1lKCIxIiA9IHJlcCgwLDUpLCIyIiA9IHJlcCgwLDUpLCIzIiA9IHJlcCgwLDUpLHJvdy5uYW1lcyA9YygiTGluZWFsaWRhZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcm1hbGlkYWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWRpYSA9IDAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWYXJpYW56YSBjb25zdGFudGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JyZWxhY2nDs24iKSkNCg0KDQpjb2xuYW1lcyhkZl9wdmFsX2Ryb3BfcDEpIDwtICAgIGMoInRyYWluMTogTCIsInRyYWluMTogTCwgc2luIGluZmx1eWVudGVzIiwgIlRlc3QgdXRpbGl6YWRvIikNCg0KZGZfcHZhbF9kcm9wX3AxWzEsXSA8LSBmaWxhX2xpbmVhbGlkYWQNCmRmX3B2YWxfZHJvcF9wMVsyLF0gPC0gZmlsYV9ub3JtYWxpZGFkDQpkZl9wdmFsX2Ryb3BfcDFbMyxdIDwtIGZpbGFfbWVkaWFPDQpkZl9wdmFsX2Ryb3BfcDFbNCxdIDwtIGZpbGFfdmFyX2N0ZQ0KZGZfcHZhbF9kcm9wX3AxWzUsXSA8LSBmaWxhX2NvcnINCmRmX3B2YWxfZHJvcF9wMQ0KYGBgDQpOdWVzdHJhcyBoaXDDs3Rlc2lzIGRlbCBtb2RlbG8gbGluZWFsIHNlIHZlbiBub3RhYmxlbWVudGUgbWVqb3JhZGFzLCB0ZW5lbW9zIHVuYSBkaXN0cmlidWNpw7NuIG3DoXMgcGFyZWNpZGEgYSB1bmEgbm9ybWFsLCBtZWpvciBkaXN0cmlidWlkYSBlbiB0b3JubyBhIHVuYSBsaW5lYWwuICANClJlYWxpemFtb3MgdW4gcGVxdWXDsW8gaW50ZXJjYW1iaW8gZW4gZWwgcXVlIG51ZXN0cmEgdmFyaWFuemEgcGFyZWNlIG1lbm9zIGNvbnN0YW50ZSBwZXJvIHNlIG1hbnRpZW5lIHBvciBlbmNpbWEgZGUgdG9kb3MgbG9zIG5pdmVsZXMgZGUgc2lnbmlmaWNhY2nDs24gaGFiaXR1YWxlcy4gIA0KVG9tYW1vcyBsYSBkZWNpc2nDs24gZGUgYWN0dWFsaXphciAqY2hlZGRhclt0cmFpbi4xLF0qIGNvbiAgKmNoZWRkYXJbdHJhaW5pbmYuMSxdKiwgcXVlIGVzIGxhIHZlcnNpw7NuIHNpbiBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzLg0KIyMjIHRhc3RlIH4gSDJTICsgTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0gdnMgdGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjFjcml0aW5mLF0NCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQp0cmFpbi4xYXV4PC10cmFpbi4xDQp0cmFpbi4xPC10cmFpbi4xaW5mDQptb2RlbC4xPC1tb2RlbC4xaW5mDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCnBvc18xY3JpdDwtYyhUUlVFLHJlcChGQUxTRSwxMCksVFJVRSxyZXAoRkFMU0UsMTApLFRSVUUscmVwKEZBTFNFLDcpKQ0KDQp0cmFpbi4xY3JpdGluZjwtdHJhaW4uMWF1eCYhcG9zXzFjcml0DQptb2RlbC4xY3JpdGluZjwtIGxtKHRhc3RlIH5IMlMrTGFjdGljICwgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMWNyaXRpbmYsXSkNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnR9DQoNCmZpbGFfbGluZWFsaWRhZCA8LSBjKHJvdW5kKHJlc2V0dGVzdChtb2RlbC4xY3JpdCwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMSxdKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQocmVzZXR0ZXN0KG1vZGVsLjFjcml0aW5mLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4xY3JpdGluZixdKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgIlJlc2V0dGVzdCIpDQoNCg0KZmlsYV9ub3JtYWxpZGFkIDwtIGMocm91bmQoc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjFjcml0KSkkcC52YWx1ZSwzKSwNCiAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xY3JpdGluZikpJHAudmFsdWUsMyksDQogICAgICAgICAgICAgICAgICAgICAiVGVzdCBTaGFwaXJvIFdpbGsiKQ0KZmlsYV9tZWRpYU8gPC0gYyh0LnRlc3QocmVzaWQobW9kZWwuMWNyaXQpLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpJHAudmFsdWUsDQogICAgICAgICAgICAgICAgIHQudGVzdChyZXNpZChtb2RlbC4xY3JpdGluZiksIG11ID0gMCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikkcC52YWx1ZSwNCiAgICAgICAgICAgICAgICAgInQtdGVzdCIpDQpmaWxhX3Zhcl9jdGUgPC0gYyhyb3VuZChuY3ZUZXN0KG1vZGVsLjFjcml0KSRwLDMpLA0KICAgICAgICAgICAgICAgICAgcm91bmQobmN2VGVzdChtb2RlbC4xY3JpdGluZikkcCwzKSwNCiAgICAgICAgICAgICAgICAgICJUZXN0IG5jdiIpDQogICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIA0KZmlsYV9jb3JyIDwtIGMoZHVyYmluV2F0c29uVGVzdChtb2RlbC4xY3JpdCkkcCwNCiAgICAgICAgICAgICAgIGR1cmJpbldhdHNvblRlc3QobW9kZWwuMWNyaXRpbmYpJHAsDQogICAgICAgICAgICAgICAiVGVzdCBkZSBEdXJiaW4tV2F0c29uIikNCiANCmRmX3B2YWxfZHJvcF9wMSA8LSBkYXRhLmZyYW1lKCIxIiA9IHJlcCgwLDUpLCIyIiA9IHJlcCgwLDUpLCIzIiA9IHJlcCgwLDUpLHJvdy5uYW1lcyA9YygiTGluZWFsaWRhZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcm1hbGlkYWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWRpYSA9IDAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWYXJpYW56YSBjb25zdGFudGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb3JyZWxhY2nDs24iKSkNCg0KDQpjb2xuYW1lcyhkZl9wdmFsX2Ryb3BfcDEpIDwtICAgIGMoInRyYWluMTogSDJTICsgTCIsInRyYWluMTogSDJTICsgTCwgc2luIGluZmx1eWVudGVzIiwgIlRlc3QgdXRpbGl6YWRvIikNCg0KZGZfcHZhbF9kcm9wX3AxWzEsXSA8LSBmaWxhX2xpbmVhbGlkYWQNCmRmX3B2YWxfZHJvcF9wMVsyLF0gPC0gZmlsYV9ub3JtYWxpZGFkDQpkZl9wdmFsX2Ryb3BfcDFbMyxdIDwtIGZpbGFfbWVkaWFPDQpkZl9wdmFsX2Ryb3BfcDFbNCxdIDwtIGZpbGFfdmFyX2N0ZQ0KZGZfcHZhbF9kcm9wX3AxWzUsXSA8LSBmaWxhX2NvcnINCg0KDQoNCg0KZGZfcHZhbF9kcm9wX3AxDQoNCg0KYGBgDQpFc3RlIGVzIHVuIGNhc28gdW4gdGFudG8gcGFydGljdWxhciwgdGVuZW1vcyB1bm9zIGRhdG9zIHBlcmZlY3RhbWVudGUgZGlzdHJpYnVpZG9zLCBwZXJvIHlhIGxvIGVzdGFiYW4gYW50ZXMgcHJhY3RpY2FtZW50ZS4gQSBjYW1iaW8gZGUgZXNvIHBlcmRlbW9zIHVuIGNpZXJ0byBncmFkbyBkZSBsaW5lYWxpZGFkIHF1ZSBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSwgZW4gZXN0ZSBjYXNvIG5vIGhheSB1bmEgZGlmZXJlbmNpYSB0YW4gbm90YWJsZSBjb24gZWwgbW9kZWxvIGNvbW8gZW4gcXVlIHNvbG8gaW5jb3Jwb3JhYmEgYSBMYWN0aWMuICANCg0KVG9tYW1vcyBsYSBkZWNpc2nDs24gZGUgYWN0dWFsaXphciAqY2hlZGRhclt0cmFpbi4xY3JpdCxdKiBjb24gICpjaGVkZGFyW3RyYWluLjFjcml0aW5mLF0qLCBxdWUgZXMgbGEgdmVyc2nDs24gc2luIG9ic2VydmFjaW9uZXMgaW5mbHV5ZW50ZXMuDQoNCiMjIyB0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMixdIHZzIHRhc3RlIH4gSDJTICsgTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4yaW5mLF0NCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQp0cmFpbi4xY3JpdDwtdHJhaW4uMWNyaXRpbmYNCm1vZGVsLjFjcml0PC0gbW9kZWwuMWNyaXRpbmYNCmBgYA0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpwb3NfMjwtYyhyZXAoRkFMU0UsNSksVFJVRSxyZXAoRkFMU0UsMjQpKQ0KDQp0cmFpbi4yaW5mPC10cmFpbi4yJiFwb3NfMg0KbW9kZWwuMmluZjwtIGxtKHRhc3RlIH4gSDJTK0xhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMmluZixdKQ0KYGBgDQoNCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnR9DQoNCmZpbGFfbGluZWFsaWRhZCA8LSBjKHJvdW5kKHJlc2V0dGVzdChtb2RlbC4yLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4yLF0pJHAudmFsdWUsMyksDQogICAgICAgICAgICAgICAgICAgICByb3VuZChyZXNldHRlc3QobW9kZWwuMmluZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMmluZixdKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgIlJlc2V0dGVzdCIpDQoNCg0KZmlsYV9ub3JtYWxpZGFkIDwtIGMocm91bmQoc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjIpKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjJpbmYpKSRwLnZhbHVlLDMpLA0KICAgICAgICAgICAgICAgICAgICAgIlRlc3QgU2hhcGlybyBXaWxrIikNCmZpbGFfbWVkaWFPIDwtIGModC50ZXN0KHJlc2lkKG1vZGVsLjIpLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpJHAudmFsdWUsDQogICAgICAgICAgICAgICAgIHQudGVzdChyZXNpZChtb2RlbC4yaW5mKSwgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSRwLnZhbHVlLA0KICAgICAgICAgICAgICAgICAidC10ZXN0IikNCmZpbGFfdmFyX2N0ZSA8LSBjKHJvdW5kKG5jdlRlc3QobW9kZWwuMikkcCwzKSwNCiAgICAgICAgICAgICAgICAgIHJvdW5kKG5jdlRlc3QobW9kZWwuMmluZikkcCwzKSwNCiAgICAgICAgICAgICAgICAgICJUZXN0IG5jdiIpDQogICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIA0KZmlsYV9jb3JyIDwtIGMoZHVyYmluV2F0c29uVGVzdChtb2RlbC4yKSRwLA0KICAgICAgICAgICAgICAgZHVyYmluV2F0c29uVGVzdChtb2RlbC4yaW5mKSRwLA0KICAgICAgICAgICAgICAgIlRlc3QgZGUgRHVyYmluLVdhdHNvbiIpDQogDQpkZl9wdmFsX2Ryb3BfcDEgPC0gZGF0YS5mcmFtZSgiMSIgPSByZXAoMCw1KSwiMiIgPSByZXAoMCw1KSwiMyIgPSByZXAoMCw1KSxyb3cubmFtZXMgPWMoIkxpbmVhbGlkYWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3JtYWxpZGFkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVkaWEgPSAwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmFyaWFuemEgY29uc3RhbnRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29ycmVsYWNpw7NuIikpDQoNCg0KY29sbmFtZXMoZGZfcHZhbF9kcm9wX3AxKSA8LSAgICBjKCJ0cmFpbjI6IEgyUyArIEwiLCJ0cmFpbjI6IEgyUyArIEwsIHNpbiBpbmZsdXllbnRlcyIsICJUZXN0IHV0aWxpemFkbyIpDQoNCmRmX3B2YWxfZHJvcF9wMVsxLF0gPC0gZmlsYV9saW5lYWxpZGFkDQpkZl9wdmFsX2Ryb3BfcDFbMixdIDwtIGZpbGFfbm9ybWFsaWRhZA0KZGZfcHZhbF9kcm9wX3AxWzMsXSA8LSBmaWxhX21lZGlhTw0KZGZfcHZhbF9kcm9wX3AxWzQsXSA8LSBmaWxhX3Zhcl9jdGUNCmRmX3B2YWxfZHJvcF9wMVs1LF0gPC0gZmlsYV9jb3JyDQoNCg0KZGZfcHZhbF9kcm9wX3AxDQpgYGANCkVuIGNpZXJ0YSBtYW5lcmEgZXMgbm90YWJsZSBxdWUgYWwgZWxpbWluYXIgbnVlc3RyYXMgaW5mbHV5ZW50ZXMgeSBlbiB1biAqZGF0YXNldCogdGFuIHBlcXVlw7FvIG5vIGdlbmVyZSBhIHBlbmFzIGRpZmVyZW5jaWEsIGVuIHRvZG8gY2FzbyBub3MgbWVqb3JhIHRvZGFzIGxhcyBoaXDDs3Rlc2lzIGRlbCBtb2RlbG8gbGluZWFsLCBzZSBwdWVkZSBhZmlybWFyIHF1ZSBlcyB1biBtb2RlbG8gbWVqb3IgcGFyYSB0cmFiYWphciBzb2JyZSBlbCBhIHByaW9yaS4gIA0KDQpUb21hbW9zIGxhIGRlY2lzacOzbiBkZSBhY3R1YWxpemFyICpjaGVkZGFyW3RyYWluLjIsXSogY29uICAqY2hlZGRhclt0cmFpbmluZi4yLF0qLCBxdWUgZXMgbGEgdmVyc2nDs24gc2luIG9ic2VydmFjaW9uZXMgaW5mbHV5ZW50ZXMuDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KdHJhaW4uMjwtdHJhaW4uMmluZg0KbW9kZWwuMjwtbW9kZWwuMmluZg0KYGBgDQojIyMgdGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjMsXSAgDQpFbiBlc3RlIG1vZGVsbywgYmFqbyBlbCBjcml0ZXJpbyBkZSBlbGVjY2nDs24gZGUgb2JzZXJ2YWNpb25lcyBpbmZsdXllbnRlcyBxdWUgZWxlZ2ltb3MgcGFyYSB0cmF0YXIgbnVlc3Ryb3MgZGF0b3MsIGVzdGUgbW9kZWxvIG5vIHByZXNlbnRhYmEgbmluZ3VuYSBvYnNlcnZhY2nDs24gaW5mbHV5ZW50ZSwgcG9yIGxvIHF1ZSBzZSBtYW50aWVuZSBjb21vIGVzdMOhLg0KDQoNCiMgRXJyb3JlcyBkZSBUZXN0LiBDb21wYXJhY2lvbiBkZSBNb2RlbG9zDQoNCg0KDQpOdWVzdHJvIHJhem9uYW1pZW50byBwYXJhIGVuZnJlbnRhcm5vcyBhIGVzdGEgc2VjY2nDs24gZXMgZWwgc2lndWllbnRlLCBub3MgaGFuIHNhbGlkbyBkb3MgbW9kZWxvcyBwb3NpYmxlcyB5IHBhcmEgY29tcHJlbmRlciBjdWFsIHNlIGFqdXN0YSBtZWpvciBhIG51ZXN0cm9zIGRhdG9zIHZhbW9zIGEgZXNjb2dlciBjaW5jbyBzZWVkcyB5IGV2YWx1YXIgY2FkYSBtb2RlbG8gZW4gdG9kYXMgZWxsYXMsIGEgZmluIGRlIGhhY2VyIHVuYSBtZWRpYSBkZSBsb3MgZXJyb3Jlcy4NCg0KUGFyYSBlc3RvIHVzYW1vcyBsYXMgdHJlcyBzZWVkcyBxdWUgaGVtb3MgdXRpbGl6YWRvIGEgbG8gbGFyZ28gZGVsIGRvY3VtZW50bywgeSBsZSBhw7FhZGltb3Mgb3RyYXMgZG9zIGVsZWdpZGFzIGFsIGF6YXIuIE7Ds3Rlc2UgcXVlIGV2YWx1YXIgZW4gbGEgcHJpbWVyYSBzZWVkIHlhIGVzdMOhIGhlY2hvLCBwdWVzIGVuIGVzdGEgbm9zIHNhbMOtYW4gbG9zIGRvcyBtb2RlbG9zIGEgY29uc2lkZXJhci4gQWRlbcOhcyBlbiBsYXMgc2VlZHMgZG9zIHkgdHJlcyB5YSBlc3TDoSBoZWNobyBwYXJhIGVsIG1vZGVsbyBjb24gSDJTICsgTGFjdGljLCBwZXJvIGhheSBxdWUgcmVwZXRpciBlbCBwcm9jZXNvIHBhcmEgZWwgb3RybyBtb2RlbG8uDQpEZSBlc3RhIG1hbmVyYSByZWFsaXphbW9zIGxvcyBtaXNtb3MgY8OhbGN1bG9zIHF1ZSBsb3MgcmVhbGl6YWRvcyBlbiBsYSBwYXJ0ZSBkZSBkaWFnbsOzc3RpY28sIHNvYnJlIGxhcyBjb21iaW5hY2lvbmVzLiBFc3RvIGVzLCBub3MgYXNlZ3VyYW1vcyBxdWUgY2FkYSBtb2RlbG8gY29uIHRvZG9zIGxvcyB0cmFpbiBjdW1wbGEgbGFzIGhpcMOzdGVzaXMgZGUgbm9ybWFsaWRhZCwgbWVkaWEgZGUgZXJyb3JlcyBudWxhLCBob21vY2VkYXN0aWNpZGFkLCBsaW5lYWxpZGFkIHkgYXV0b2NvcnJlbGFjacOzbi4gRGVzcHXDqXMgZGUgZXN0byBub3MgcGxhbnRlYW1vcyBzaSB0aWVuZSBkYXRvcyBpbmZsdXllbnRlcyBzZWfDum4gbGFzIGZ1bmNpb25lcyBhZGVjdWFkYXMsIGVuIGNhc28gZGUgdGVuZXJsb3MgcmVhbGl6YW1vcyB1bmEgcHJ1ZWJhLiBsb3MgcXVpdGFtb3MgZGVsIHRyYWluIHkgdmVtb3Mgc2kgc2UgbWVqb3JhIGVsIHAtdmFsb3IgZGUgYWxndW5hIGRlIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGFudGVyaW9yZXMgeSBlbiBiYXNlIGEgZXNvIGRlY2lkaW1vcyBzaSBlbGltaW5hbW9zIGxhcyBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzIG8gbm8uIA0KDQpDb24gdG9kbyBlc28gcmVhbGl6YWRvIGxsZWdhbW9zIGEgbGEgc2lndWllbnRlIHRhYmxhLCBxdWUgbm9zIHBlcm1pdGUgYXN1bWlyIGNvbW8gdmFsaWRvcyB0b2RvcyBsb3MgY2Fzb3MgeSBjYWxjdWxhciBzdXMgZXJyb3Jlcy4NCg0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQojIElOVFJPRFVDSVIgU0VDQ0lPTiA1DQojIENPTVBMRVRBUiBUQUJMQSBPVVRMSUVSUw0KIyBDUkVPIFFVRSBURU5JQSBRVUUgUE9ORVIgSE9NT0VTVCBBUlJJQkENCiMgSlVTVE8gRU4gRUwgU1VNTUFSWSBERSBMQSBTRUNDSU9OIDYgQ1JFTyBRVUUgRUwgREFUQSBOTyBERUJFUklBIFNFUiBDSEVEREFSDQoNCiMgVmFtb3MgYSBjb25zaWRlcmFyIG90cmFzIGRvcyBzZW1pbGxhcyBwYXJhIGV2YWx1YXIgbG9zIG1vZGVsb3MgeSBlbGVnaXIgZWwgbWVqb3IuDQojIExhcyB0b21hbW9zIGRlIGZvcm1hIHF1ZSBubyBjb2luY2lkYW4gZW4gbGEgbWVkaWRhIGRlIGxvIHBvc2libGUgbG9zIHRlc3RzIGRlIGxhcyBkaXN0aW50YXMgcGFydGljaW9uZXMuDQojIERpdmlkaW1vcyBlbCBjb25qdW50byB0b3RhbCBwYXJhIGxhcyBkb3Mgc2VtaWxsYXMgbnVldmFzLg0KDQpzZXQuc2VlZCgoMjIzNCkpDQp0cmFpbi40IDwtIHNhbXBsZShjKFRSVUUsIEZBTFNFKSwgc2l6ZSA9IG5yb3coY2hlZGRhciksIHJlcGxhY2UgPSBUUlVFLCBwcm9iID0gYygwLjcsIDAuMykpDQp0ZXN0LjQgPC0gKCF0cmFpbi40KQ0Kc3VtKHRlc3QuNCkNCnN1bSh0ZXN0LjE9PVRSVUUgJiB0ZXN0LjQ9PVRSVUUpDQpzdW0odGVzdC4yPT1UUlVFICYgdGVzdC40PT1UUlVFKQ0Kc3VtKHRlc3QuMz09VFJVRSAmIHRlc3QuND09VFJVRSkNCg0KDQpzZXQuc2VlZCgoMTMxKSkNCnRyYWluLjUgPC0gc2FtcGxlKGMoVFJVRSwgRkFMU0UpLCBzaXplID0gbnJvdyhjaGVkZGFyKSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSBjKDAuNywgMC4zKSkNCnRlc3QuNSA8LSAoIXRyYWluLjUpDQpzdW0odGVzdC41KQ0Kc3VtKHRlc3QuMT09VFJVRSAmIHRlc3QuNT09VFJVRSkNCnN1bSh0ZXN0LjI9PVRSVUUgJiB0ZXN0LjU9PVRSVUUpDQpzdW0odGVzdC4zPT1UUlVFICYgdGVzdC41PT1UUlVFKQ0Kc3VtKHRlc3QuND09VFJVRSAmIHRlc3QuNT09VFJVRSkNCg0KdHJhaW4uMWggPC0gdHJhaW4uMWNyaXQNCnRyYWluLjJoIDwtIHRyYWluLjINCnRyYWluLjNoIDwtIHRyYWluLjMNCnRyYWluLjRoIDwtIHRyYWluLjQNCnRyYWluLjVoIDwtIHRyYWluLjUNCg0KIyBSZWNhbGN1bGFtb3MgdHJhaW4uMiBwb3JxdWUgZnVlIG1vZGlmaWNhZG8NCnNldC5zZWVkKDExMDApDQp0cmFpbi4yIDwtIHNhbXBsZShjKFRSVUUsIEZBTFNFKSwgc2l6ZSA9IG5yb3coY2hlZGRhciksIHJlcGxhY2UgPSBUUlVFLCBwcm9iID0gYygwLjcsIDAuMykpDQoNCg0KDQoNCiMgVmVhbXNvIHNpIHBvZGVtb3MgZWxpbWluYXIgcG9zaWJsZXMgaW5mbHV5ZW50ZXMgZW4gbG9zIG1vZGVsb3MgcmVzdGFudGVzDQoNCm1oMSA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMWgsXSkgIyBjb21wcm9iYWRvcyBzdXB1ZXN0b3MNCm1oMiA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMmgsXSkgIyBjb21wcm9iYWRvcyBzdXB1ZXN0b3MNCm1oMyA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uM2gsXSkgIyBjb21wcm9iYWRvcyBzdXB1ZXN0b3MNCm1oNCA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNGgsXSkNCm1oNSA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNWgsXSkNCg0KbTEgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjEsXSkgIyBjb21wcm9iYWRvcyBzdXB1ZXN0b3MNCm0yIDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4yLF0pDQptMyA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMyxdKQ0KbTQgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjQsXSkNCm01IDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi41LF0pDQoNCg0KIyBBbCBpZ3VhbCBxdWUgaGljaW1vcyBlbiA0IGNvbXByb2JhbW9zIHNpIHJldGlyYW5kbyBvdXRsaWVycyB5IG9ic2VydmFjaW9uZXMgaW5mbHV5ZW50ZXMgbWVqb3JhbiBsYXMgaGlwb3Rlc2lzLg0KIyAgVW5pY2FtZW50ZSBjb25zaWRlcmFyZW1vcyBvYnNlcnZhY2lvbmVzIG9idGVuaWRhcyB0YW50byBwb3Igb3V0bGllclRlc3QoKSBjb21vIHBvciBpbmZsdWVuY2VQbG90KCkuDQoNCiMgbWg0DQpvdXRsaWVyVGVzdChtaDQpDQppbmZsdWVuY2VQbG90KG1oNCkgIyA2LDEyLDE1LDI0DQpwb3M0aCA8LSBjKHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSwyKSxUUlVFLHJlcChGQUxTRSw4KSxUUlVFLHJlcChGQUxTRSw2KSkNCg0KdHJhaW4uNGluZiA8LSB0cmFpbi40aCYhcG9zNGgNCm1oNGluZiA8LSBsbSh0YXN0ZSB+IEgyUytMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjRpbmYsXSkNCg0KbmN2VGVzdChtaDQpDQpuY3ZUZXN0KG1oNGluZikgIyBtZWpvcmEgTVVDSE8NCg0Kc2hhcGlyby50ZXN0KHJlc2lkKG1oNCkpDQpzaGFwaXJvLnRlc3QocmVzaWQobWg0aW5mKSkgIyBtZWpvcmENCg0KZHVyYmluV2F0c29uVGVzdChtaDQpDQpkdXJiaW5XYXRzb25UZXN0KG1oNGluZikgIyBtZWpvcmENCg0KcmVzZXR0ZXN0KG1oNCwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNGluZixdKSANCnJlc2V0dGVzdChtaDRpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjRpbmYsXSkgIyBlbXBlb3JhIHBlcm8gZXMgYWNlcHRhYmxlDQoNCiMgUmVkZWZpbmltb3MgZWxpbWluYW5kbyBwb3M0aCBwb3Igc2VyIHRhbnRhIGxhIG1lam9yYSBlbiBob21vY2VkYXN0aWNpZGFkIHF1ZSBjb21wZW5zYSBsYSBsaW5lYWxpZGFkDQp0cmFpbi40aCA8LSB0cmFpbi40aW5mDQptaDQgPC0gbWg0aW5mDQoNCg0KIyBtaDUNCm91dGxpZXJUZXN0KG1oNSkNCmluZmx1ZW5jZVBsb3QobWg1KSAjIDYsNyw4LDEyLDE1DQpwb3M1aCA8LSBjKHJlcChGQUxTRSw1KSxUUlVFLFRSVUUsVFJVRSxyZXAoRkFMU0UsMyksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsMTUpKQ0KDQp0cmFpbi41aW5mIDwtIHRyYWluLjVoJiFwb3M1aA0KbWg1aW5mIDwtIGxtKHRhc3RlIH4gSDJTK0xhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNWluZixdKQ0KDQpuY3ZUZXN0KG1oNSkNCm5jdlRlc3QobWg1aW5mKSAjIG1lam9yYSANCg0Kc2hhcGlyby50ZXN0KHJlc2lkKG1oNSkpDQpzaGFwaXJvLnRlc3QocmVzaWQobWg1aW5mKSkgIyBlbXBlb3JhDQoNCmR1cmJpbldhdHNvblRlc3QobWg1KQ0KZHVyYmluV2F0c29uVGVzdChtaDVpbmYpICMgYSB2ZWNlcyBubyBzZSBjdW1wbGUgbGEgaGlwb3Rlc2lzIG51bGEgZGUgbm8gYXV0b2NvcnJlbGFjaW9uDQoNCnJlc2V0dGVzdChtaDUsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjVpbmYsXSkgDQpyZXNldHRlc3QobWg1aW5mLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi41aW5mLF0pICMgZW1wZW9yYQ0KDQojIERlY2lkaW1vcyBubyBhY3R1YWxpemFyIGVsIG1vZGVsbyBwdWVzIG5vIHNpZW1wcmUgc2UgcmVjaGF6YSBsYSBjb3JyZWxhY2lvbiB5IGVtcGVvcmFuIG90cm9zIHAtdmFsb3Jlcy4NCg0KDQojIG0yDQpvdXRsaWVyVGVzdChtMikNCmluZmx1ZW5jZVBsb3QobTIpICMgMSwxMiwxNSwxOCwyNA0KcG9zMiA8LSBjKFRSVUUscmVwKEZBTFNFLDEwKSxUUlVFLHJlcChGQUxTRSwyKSxUUlVFLHJlcChGQUxTRSwyKSxUUlVFLHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSw2KSkNCg0KdHJhaW4uMmluZiA8LSB0cmFpbi4yJiFwb3MyDQptMmluZiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMmluZixdKQ0KDQpuY3ZUZXN0KG0yKQ0KbmN2VGVzdChtMmluZikgIyBlbXBlb3JhIGxpZ2VyYW1lbnRlDQoNCnNoYXBpcm8udGVzdChyZXNpZChtMikpDQpzaGFwaXJvLnRlc3QocmVzaWQobTJpbmYpKSAjIGVtcGVvcmEgbGlnZXJhbWVudGUNCg0KZHVyYmluV2F0c29uVGVzdChtMikNCmR1cmJpbldhdHNvblRlc3QobTJpbmYpICMgZW1wZW9yYSBiYXN0YW50ZQ0KDQpyZXNldHRlc3QobTIsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjJpbmYsXSkgDQpyZXNldHRlc3QobTJpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjJpbmYsXSkgIyBtZWpvcmENCg0KIyBEZWNpY2ltb3Mgbm8gcmVkZWZpbmlybG8sIHlhIHF1ZSBlbXBlb3JhIGVuIG11Y2hhcyB5IG1lam9yYSBiYXN0YW50ZSBlbiB1bmENCg0KDQojIG0zDQpvdXRsaWVyVGVzdChtMykNCmluZmx1ZW5jZVBsb3QobTMpICMgMSwxNSwxOSwyNA0KcG9zMyA8LSBjKFRSVUUscmVwKEZBTFNFLDEzKSxUUlVFLHJlcChGQUxTRSwzKSxUUlVFLHJlcChGQUxTRSw0KSxUUlVFLHJlcChGQUxTRSw2KSkNCg0KdHJhaW4uM2luZiA8LSB0cmFpbi4zJiFwb3MzDQptM2luZiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uM2luZixdKQ0KDQpuY3ZUZXN0KG0zKQ0KbmN2VGVzdChtM2luZikgIyBtZWpvcmEgcG9jbw0KDQpzaGFwaXJvLnRlc3QocmVzaWQobTMpKQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG0zaW5mKSkgIyBtZWpvcmENCg0KZHVyYmluV2F0c29uVGVzdChtMykNCmR1cmJpbldhdHNvblRlc3QobTNpbmYpICMgZW1wZW9yYQ0KDQpyZXNldHRlc3QobTMsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjNpbmYsXSkgDQpyZXNldHRlc3QobTNpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjNpbmYsXSkgIyBlbXBlb3JhIGNhc2kgbG8gcGllcmRlDQoNCiMgRGVjaWRpbW9zIG5vIHJlZGVmaW5pcmxvIHBvciBlc3RhciBhbCBib3JkZSBlbiB1biBjcml0ZXJpbyB5IG5vIG1lam9yYXIgbXVjaG8gZW4gb3Ryb3MNCg0KDQojIG00DQpvdXRsaWVyVGVzdChtNCkNCmluZmx1ZW5jZVBsb3QobTQpICMgNiwxMiwxNSwyMCwyNA0KcG9zNCA8LSBjKHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSwyKSxUUlVFLHJlcChGQUxTRSw0KSxUUlVFLHJlcChGQUxTRSwzKSxUUlVFLHJlcChGQUxTRSw2KSkNCg0KdHJhaW4uNGluZiA8LSB0cmFpbi40JiFwb3M0DQptNGluZiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNGluZixdKQ0KDQpuY3ZUZXN0KG00KQ0KbmN2VGVzdChtNGluZikgIyBlbXBlb3JhIGJhc3RhbnRlDQoNCnNoYXBpcm8udGVzdChyZXNpZChtNCkpDQpzaGFwaXJvLnRlc3QocmVzaWQobTRpbmYpKSAjIGVtcGVvcmENCg0KZHVyYmluV2F0c29uVGVzdChtNCkNCmR1cmJpbldhdHNvblRlc3QobTRpbmYpIyBlbXBlb3JhIGJhc3RhbnRlDQoNCnJlc2V0dGVzdChtNCwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNGluZixdKSANCnJlc2V0dGVzdChtNGluZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNGluZixdKSAjIG1lam9yYSBhbGdvDQoNCiMgRGVjaWRpbW9zIG5vIGNhbWJpYXJsbyBwb3JxdWUgZW1wZW9yYSBlbiBjYXNpIHRvZG8sIHkgZGUgcG9yIHNpIHRlbmlhIGJ1ZW5vcyBwLXZhbHVlcw0KDQoNCiMgbTUNCm91dGxpZXJUZXN0KG01KQ0KaW5mbHVlbmNlUGxvdChtNSkgIyAxLDgsMTIsMTUsMTgsMjQNCnBvczUgPC0gYyhUUlVFLHJlcChGQUxTRSw2KSxUUlVFLHJlcChGQUxTRSwzKSxUUlVFLHJlcChGQUxTRSwyKSxUUlVFLHJlcChGQUxTRSwyKSxUUlVFLHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSw2KSkNCg0KdHJhaW4uNWluZiA8LSB0cmFpbi41JiFwb3M1DQptNWluZiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNWluZixdKQ0KDQpuY3ZUZXN0KG01KQ0KbmN2VGVzdChtNWluZikgIyBlbXBlb3JhIGJhc3RhbnRlDQoNCnNoYXBpcm8udGVzdChyZXNpZChtNSkpDQpzaGFwaXJvLnRlc3QocmVzaWQobTVpbmYpKSAjIG1lam9yYSANCg0KZHVyYmluV2F0c29uVGVzdChtNSkNCmR1cmJpbldhdHNvblRlc3QobTVpbmYpICMgbm8gc2UgdmVyaWZpY2EgbGEgaGlwb3Rlc2lzIG51bGEgZGUgbm8gYXV0b2NvcnJlbGFjaW9uDQoNCnJlc2V0dGVzdChtNSwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNWluZixdKSANCnJlc2V0dGVzdChtNWluZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNWluZixdKSAjIGVtcGVvcmENCg0KIyBEZWNpZGltb3Mgbm8gY2FtYmlhcmxvIHBvciBwZXJkZXJzZSBsYSBjb3JyZWxhY2nDs24NCg0KIyBOb3Rlc2UgcXVlIGVuIGxvcyBvcmlnaW5hbGVzIHNpZW1wcmUgc2UgY3VtcGxpYW4gbGFzIGhpcG90ZXNpcywgYXVucXVlIG5vIGVyYSBuZWNlc2FyaW8gcGFyYSBlbCBwcm9jZXNvDQoNCg0KDQoNCmxpc3RhX3Rlc3QgPC0gbGlzdCh0ZXN0LjEsdGVzdC4yLHRlc3QuMyx0ZXN0LjQsdGVzdC41KQ0KbGlzdGFfdHJhaW5oIDwtIGxpc3QodHJhaW4uMWgsdHJhaW4uMmgsdHJhaW4uM2gsdHJhaW4uNGgsdHJhaW4uNWgpDQpsaXN0YV90cmFpbiA8LSBsaXN0KHRyYWluLjEsdHJhaW4uMix0cmFpbi4zLHRyYWluLjQsdHJhaW4uNSkNCg0KDQptb2RlbG9zX2hpcCA8LSBjKCJTMSB0YXN0ZSB+IEgycyArIExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTMSB0YXN0ZSB+IExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTMiB0YXN0ZSB+IEgycyArIExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTMiB0YXN0ZSB+IExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTMyB0YXN0ZSB+IEgycyArIExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTMyB0YXN0ZSB+IExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTNCB0YXN0ZSB+IEgycyArIExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTNCB0YXN0ZSB+IExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTNSB0YXN0ZSB+IEgycyArIExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJTNSB0YXN0ZSB+IExhY3RpYyIsDQogICAgICAgICAgICAgICAgICJOaXZlbCBkZSBzaWduaWZpY2FjaW9uIikNCg0KaGlwX1JMIDwtIGMoIkRpc3RyaWJ1Y2nDs25fbm9ybWFsIiwNCiAgICAgICAgICAgICJNZWRpYV8wIiwNCiAgICAgICAgICAgICJWYXJpYW56YV9ub19jb25zdGFudGUiLA0KICAgICAgICAgICAgIk5vX0F1dG9jb3JyZWxhY2nDs24iKQ0KcGxhY2Vob2xkZXIgPC0gdmVjdG9yKG1vZGUgPSAibG9naWNhbCIsbGVuZ3RoID0gMTEpDQpkZl9oaXBSTCA8LSBkYXRhLmZyYW1lKCIwIiA9IHBsYWNlaG9sZGVyLA0KICAgICAgICAgICAgICAgICAgICAgICAiMSIgPSBwbGFjZWhvbGRlciwNCiAgICAgICAgICAgICAgICAgICAgICAgIjIiID0gcGxhY2Vob2xkZXIsDQogICAgICAgICAgICAgICAgICAgICAgICIzIiA9IHBsYWNlaG9sZGVyLA0KICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBtb2RlbG9zX2hpcCkNCg0KY29sbmFtZXMoZGZfaGlwUkwpIDwtIGhpcF9STA0KDQpyIDwtIDENCmZvciAoZHRyYWluIGluIGxpc3RhX3RyYWluaCl7DQogIG1vZGVsLkhMLmxtIDwtIGxtKHRhc3RlIH4gSDJTICsgTGFjdGljLA0KICAgICAgICAgICAgICAgICAgICBkYXRhID0gY2hlZGRhcltkdHJhaW4sXSkNCiAgcmVzaWR1b3MgPC0gcmVzaWQobW9kZWwuSEwubG0pDQogIG5ld19yb3cgPC0gYygpDQogIA0KICBzaGFwIDwtIHJvdW5kKHNoYXBpcm8udGVzdChyZXNpZHVvcykkcC52YWx1ZSw0KQ0KICB0IDwtIHQudGVzdChyZXNpZHVvcywgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSRwLnZhbHVlDQogIHYgPC0gcm91bmQobmN2VGVzdChtb2RlbC5ITC5sbSkkcCw0KQ0KICBkdyA8LSByb3VuZChkdXJiaW5XYXRzb25UZXN0KG1vZGVsLkhMLmxtKSRwLDQpDQogIA0KICBuZXdfcm93ID0gYyhzaGFwLHQsdixkdykNCiAgZGZfaGlwUkxbcixdIDwtIG5ld19yb3cNCiAgciA9IHIgKyAyDQp9DQoNCg0KciA8LSAyDQpmb3IgKGR0cmFpbiBpbiBsaXN0YV90cmFpbil7DQogIG1vZGVsLkwubG0gPC0gbG0odGFzdGUgfkxhY3RpYywNCiAgICAgICAgICAgICAgICAgICBkYXRhID0gY2hlZGRhcltkdHJhaW4sXSkNCiAgcmVzaWR1b3MgPC0gcmVzaWQobW9kZWwuTC5sbSkNCiAgbmV3X3JvdyA8LSBjKCkNCiAgDQogIHNoYXAgPC0gcm91bmQoc2hhcGlyby50ZXN0KHJlc2lkdW9zKSRwLnZhbHVlLDQpDQogIHQgPC0gdC50ZXN0KHJlc2lkdW9zLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpJHAudmFsdWUNCiAgdiA8LSByb3VuZChuY3ZUZXN0KG1vZGVsLkwubG0pJHAsNCkNCiAgZHcgPC0gcm91bmQoZHVyYmluV2F0c29uVGVzdChtb2RlbC5MLmxtKSRwLDQpDQogIA0KICBuZXdfcm93ID0gYyhzaGFwLHQsdixkdykNCiAgZGZfaGlwUkxbcixdIDwtIG5ld19yb3cNCiAgciA9IHIgKyAyDQp9DQpkZl9oaXBSTFsxMSxdIDwtIGMocmVwKDAuMDUsNCkpDQpkZl9oaXBSTCAjIFRvZG9zIGxvcyBtb2RlbG9zIGN1bXBsZW4gbGFzIGhpcMOzdGVzaXMNCg0KDQoNCmVycjEgPC0gMA0KZm9yIChpIGluIDUpew0KICBkdHJhaW4gPC0gbGlzdGFfdHJhaW5oW1tpXV0NCiAgZHRlc3QgPC0gbGlzdGFfdGVzdFtbaV1dDQogIGRtb2QgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW2R0cmFpbixdKQ0KICBZIDwtIGNoZWRkYXJbZHRlc3QsXSR0YXN0ZQ0KICBZaGF0IDwtIHByZWRpY3Qob2JqID0gZG1vZCwgbmV3ZGF0YSA9IGNoZWRkYXJbZHRlc3QsXSkNCiAgZXJyMSA8LSBlcnIxICsgbWVhbigoWSAtIFloYXQpXjIpDQp9DQplcnIxIDwtIGVycjEvNQ0KZXJyMSAjIEgyUyArIExBQ1RJQyB0aWVuZSBlcnJvciBtZWRpbyAxMS42Mw0KDQoNCmVycjI8LTANCmZvciAoaSBpbiA1KXsNCiAgZHRyYWluIDwtIGxpc3RhX3RyYWluW1tpXV0NCiAgZHRlc3QgPC0gbGlzdGFfdGVzdFtbaV1dDQogIGRtb2QgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW2R0cmFpbixdKQ0KICBZIDwtIGNoZWRkYXJbZHRlc3QsXSR0YXN0ZQ0KICBZaGF0IDwtIHByZWRpY3Qob2JqID0gZG1vZCwgbmV3ZGF0YSA9IGNoZWRkYXJbZHRlc3QsXSkNCiAgZXJyMiA8LSBlcnIyICsgbWVhbigoWSAtIFloYXQpXjIpDQp9DQoNCg0KYGBgDQpgYGB7ciByZW5kZXI9bGVtb25fcHJpbnQsIGVjaG89RkFMU0V9DQpkZl9oaXBSTA0KDQoNCmBgYA0KQ2FsY3VsYW1vcyBsb3MgZXJyb3JlcyBkZSBjYWRhIG3DqXRvZG8gY29tbyBsYSBtZWRpYSBkZSBsb3MgZXJyb3JlcyBkZWwgbcOpdG9kbyBhcGxpY2FkbyBlbiBjYWRhIHNlZWQuIERlIGVzdGEgbWFuZXJhLCBlbCBlcnJvciBtZWRpbyBvYnRlbmlkbyBlczoNCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnQgfQ0KZHQ8LWRhdGEuZnJhbWUoIjEiPTAsIjIiPTAscm93Lm5hbWVzPWMoImVycm9yZXMiKSkNCmNvbG5hbWVzKGR0KTwtIGMoIk1vZGVsbyBIMlMrTGFjdGljIiwiTGFjdGljIikNCmR0WzEsXTwtYyhlcnIxLGVycjIpDQpkdA0KYGBgDQoNCkNvbW8gZWwgZXJyb3IgZGVsIG1vZGVsbyBIMlMgKyBMYWN0aWMgZXMgbWVub3IsIGVzZSBlcyBlbCBtb2RlbG8gcXVlIGxsYW1hcmVtb3MgZmluYWwgeSBxdWUgc2UgYWp1c3RhcsOhIGxvIG1lam9yIHBvc2libGUgYSBsb3MgZGF0b3MgZGUgbnVlc3RybyBmaWNoZXJvLg0KDQojIENvbmNsdXNpw7NuOiBwcmVzZW50YWNpw7NuIGRlbCBtb2RlbG8gZmluYWwNCg0KRmluYWxtZW50ZSBwb3IgY29tcGFyYWNpw7NuIGRlIGxvcyBlcnJvcmVzIHNhYmVtb3MgcXVlIGVsIG1vZGVsbyBmaW5hbCBxdWUgcHJlc2VudGFtb3MgZXM6IHRhc3RlIH4gSDJTICsgTGFjdGljICwgcXVlIHRpZW5lIHNlbnRpZG8geWEgcXVlIEFjZXRpYyBubyBlcmEgc2lnbmlmaWNhdGl2YS4gb3RybyBoZWNobyBxdWUgbG8gcmVhZmlybWEgZXMgcXVlIGVuIGxhIGNvbnN0cnVjY2nDs24gZGUgbW9kZWxvcyBzYWxpZXJvbiBlbiB0b2RvcyBsb3MgY2Fzb3MgZXN0ZSBtb2RlbG8sIHNhbHZvIGVuIGVsIG3DqXRvZG8gYmFja3dhcmQgeSBlbiBlbCBtw6l0b2RvIGZvcndhcmQgZGUgbGEgcHJpbWVyYSBzZW1pbGxhLg0KDQo8IS0tIGFxdWkgaGFjZXJsbyB0YWJsYSBjb24gbG8gcXVlIG1lIGludGVyZXNhIC0tPg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCm1vZGVsLnkgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsZGF0YT1jaGVkZGFyKSANCmRmX3Jlc3VtZW4gPC0gdGlkeShtb2RlbC55KQ0KDQoNCmBgYA0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KZGZfcmVzdW1lbg0KYGBgDQoNClByZXNlbnRhbW9zIGVsIHN1bW1hcnkgZGUgbnVlc3RybyBtb2RlbG8sIGRlbCBxdWUgc2FjYXJlbW9zIG3DoXMgaW5mb3JtY2nDs24gZW4gdW4gZnV0dXJvLg0KDQpBIHN1IHZleiBlbnNlw7FhbW9zIGxvcyBncmFmaWNvcyBkZSBlc3RlIG1vZGVsbzoNCmBgYHtyIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTYuNSxmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KG1vZGVsLnkpDQpgYGANCg0KQWhvcmEgdmFtb3MgYSBhc2VndXJhcm5vcyBxdWUgdmVyaWZpY2EgbGFzIGhpcMOzdGVzaXMgcGFyYSB1bmEgcmVncmVzacOzbiBsaW5lYWwgeSBhZGVtw6FzIGRlIHJldmlzYXIgY29uIG91dGxpZXJUZXN0ICBxdWUgbm8gdGVuZW1vcyBvdXRsaWVycy4NClRhbWJpw6luIHBsYW50ZWFtb3MgdW5hIGhpcMOzdGVzaXMgc29icmUgbGEgbnVsaWRhZCBkZSBsYSBtZWRpYSBkZSBsb3MgZXJyb3JlcyB5IHZlbW9zIHF1ZSBzdSB2YXJpYW56YSBlcyBjb25zdGFudGUgYWRlbcOhcyBkZSBjYWxjdWxhcmxhLg0KPCEtLSBBcXVpIGRlYmVyw61hIGlyIHRhYmxhIGNvbiBwdmFsdWVzIGRlIG5vcm1hbGlkYWQuLi4uIC0tPg0KYGBge3IgZWNobz1GQUxTRSwgcmVuZGVyPWxlbW9uX3ByaW50fQ0KZGZfcHZhbF9kcm9wX3AxIDwtIGRhdGEuZnJhbWUoIjEiID0gcmVwKDAsMSksIjIiID0gcmVwKDAsMSksIjMiID0gcmVwKDAsMSksIjQiID0gcmVwKDAsMSksIjUiID0gcmVwKDAsMSksIjYiID0gcmVwKDAsMSksIjciID0gcmVwKDAsMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXM9YygibW9kZWwueSIpKQ0KY29sbmFtZXMoZGZfcHZhbF9kcm9wX3AxKSA8LSAgICBjKCJwLU91dGxpZXJzIiwicC1Ob3JtYWxpZGFkIiwicC1NZWRpYSBudWxhIiwicC1Ib21vY2VkYXN0aWNpZGFkIiwiVmFsb3IgZGUgdmFyaWFuemEiLCJwLUF1dG9jb3JyZWxhY2nDs24iLCJwLUxpbmVhbGlkYWQiKQ0KZGZfcHZhbF9kcm9wX3AxWywxXSA8LSBvdXRsaWVyVGVzdChtb2RlbC55KSRwDQpkZl9wdmFsX2Ryb3BfcDFbLDJdIDwtIHNoYXBpcm8udGVzdChyZXNpZChtb2RlbC55KSkkcA0KZGZfcHZhbF9kcm9wX3AxWywzXSA8LSB0LnRlc3QocmVzaWQobW9kZWwueSksbXU9MCxhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSRwLnZhbHVlDQpkZl9wdmFsX2Ryb3BfcDFbLDRdIDwtIG5jdlRlc3QobW9kZWwueSkkcA0KZGZfcHZhbF9kcm9wX3AxWyw1XSA8LSBzcXJ0KGRldmlhbmNlKG1vZGVsLnkpL2RmLnJlc2lkdWFsKG1vZGVsLnkpKQ0KZGZfcHZhbF9kcm9wX3AxWyw2XSA8LSBkdXJiaW5XYXRzb25UZXN0KG1vZGVsLnkpJHANCmRmX3B2YWxfZHJvcF9wMVssN10gPC0gcmVzZXR0ZXN0KG1vZGVsLnksIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyKSRwLnZhbHVlDQpkZl9wdmFsX2Ryb3BfcDENCmBgYA0KDQpEaWNobyBlc3RvIHByb2NlZGVtb3MgYSBsYSBwcmVzZW50YWNpw7NuIGRlbCBtb2RlbG8gY29uIHN1cyBiZXRhcyBhc29jaWFkb3MsIHF1ZSBzaSBiaWVuIHNlIHB1ZWRlbiByZWNvZ2VyIGRlbCBzdW1tYXJ5LCB0YW1iacOpbiBsb3MgY2FsY3VsYW1vcyBkZSBmb3JtYSBtYXRyaWNpYWwgaWd1YWwgcXVlIHNlIGhpem8gY29uIGVsIG1vZGVsbyBjb21wbGV0byBlbiBzdSBtb21lbnRvLg0KDQpFbCByZXN1bHRhZG8gc2Vyw61hICoqdGFzdGUgfiAtMjcuNTkxODE1ICszLjk5NDYyNjcgSDJTICsxOS44ODcyMDQgTGFjdGljKioNCk7Ds3Rlc2UgcXVlIHNpZ3VlIHNpZW5kbyBhY29yZGUgYWwgbW9kZWxvIGNvbXBsZXRvIGRvbmRlIGVsICRcYmV0YSQgZGUgTGFjdGljIGVzIG11eSBzdXBlcmlvciBlbiBjb21wYXJhY2nDs24gYWwgZGUgSDJTLg0KDQpQcmVzZW50YW1vcyBhaG9yYSAkUl57Mn0kIHkgJFJeezJ9X3thZGp9JCwgZXN0YXMgY29tbyBhbnRlcyBzZSBwdWVkZW4gcmVjb2dlciBkaXJlY3RhbWVudGUgZGVsIHN1bW1hcnksIHRhbWJpw6luIGxhcyBjYWxjdWxhbW9zIGEgcGFydGlyIGRlIGxvcyBlcnJvcmVzIHkgbGEgdGFibGEgYW5vdmEsIGRhbmRvIGVsIHJlc3VsdGFkbyBkZSAwLjY1MTcwMjQgeSAwLjYyNTkwMjUgcmVzcGVjdGl2YW1lbnRlLiBBZGVtw6FzIHByZXNlbnRhbW9zIGVsIHZlY3RvciBkZSBwLXZhbG9yZXMuDQoNCjwhLS0gQXF1aSBpcmlhIHVuIHRhYmxhIHF1ZSBwcmVzZW50ZSB0b2RvIGVsbG8gLS0+DQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnR9DQojc3VtbWFyeShtb2RlbC55KSRjb2VmZlssNF0NCg0KZGZfcHZhbF9kcm9wX3AxIDwtIGRhdGEuZnJhbWUoIjEiID0gcmVwKDAsMSksIjIiID0gcmVwKDAsMSksIjMiID0gcmVwKDAsMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXM9YygiUC12YWxvcmVzIikpDQoNCmNvbG5hbWVzKGRmX3B2YWxfZHJvcF9wMSkgPC0gICAgYygiSW50ZXJjZXB0IiwiSDJTIiwiTGFjdGljIikNCmRmX3B2YWxfZHJvcF9wMVsxLF0gPC0gYyhzdW1tYXJ5KG1vZGVsLnkpJGNvZWZmW1sxLDRdXSxzdW1tYXJ5KG1vZGVsLnkpJGNvZWZmW1syLDRdXSxzdW1tYXJ5KG1vZGVsLnkpJGNvZWZmW1szLDRdXSkNCg0KZGZfcHZhbF9kcm9wX3AxDQpgYGANCk9ic2VydmFtb3MgcXVlIHRvZG9zIGxvcyBwLXZhbG9yZXMgZXN0w6FuIHBvciBkZWJham8gZGUgbnVlc3RyYSBhbHBoYSBkZSByZWZlcmVuY2lhLg0KDQpUYW1iacOpbiBwcmVzZW50YW1vcyBpbnRlcnZhbG9zIHBhcmEgbGFzIGJldGFzIGRlIEJvbmZlcnJvbmkgeSBTY2hlZmbDqToNCjwhLS0gQXF1aSB2YSBlc28gLS0+DQpgYGB7ciBlY2hvPUZBTFNFLCByZW5kZXI9bGVtb25fcHJpbnR9DQphbHBoYSA8LSAwLjEwDQpiIDwtIHN1bW1hcnkobW9kZWwueSkkY29lZlsyOjMsIDFdDQpzLmIgPC0gc3VtbWFyeShtb2RlbC55KSRjb2VmWzI6MywgMl0NCmcgPC0gMw0KbiA8LSBucm93KGNoZWRkYXIpDQpwIDwtIG5jb2woc3VtbWFyeShtb2RlbC55KSRjb2VmKQ0KdF90ZW8gPC0gcXQoMSAtIGFscGhhIC8gKDIgKiBnKSwgbiAtIHApDQpCb21TaW1DSSA8LSBtYXRyaXgoYyhiIC0gdF90ZW8gKiBzLmIsIGIgKyB0X3RlbyAqIHMuYiksIG5jb2wgPSAyKQ0KY29uZiA8LSBjKCI1JSIsICI5NSUiKQ0KYm5hbSA8LSBjKCJIMlMiLCAiTGFjdGljIikNCmRpbW5hbWVzKEJvbVNpbUNJKSA8LSBsaXN0KGJuYW0sIGNvbmYpDQojIEJvbVNpbUNJDQpjMTwtQm9tU2ltQ0lbMSxdDQpjMjwtQm9tU2ltQ0lbMixdDQpRIDwtIHAgLSAxDQpmX3RlbyA8LSBxZigwLjksIFEsIG4gLSBwKSMwLjkgbm8gc2VyaWEgMC45NT8NClNjaFNpbUNJIDwtIG1hdHJpeChjKGIgLSBzcXJ0KFEgKiBmX3RlbykgKiBzLmIsIGIgKyBzcXJ0KFEgKiBmX3RlbykgKiBzLmIpLCBuY29sID0gMikNCmNvbmYgPC0gYygiNSUiLCAiOTUlIikNCmJuYW0gPC0gYygiSDJTIiwgIkxhY3RpYyIpDQpkaW1uYW1lcyhTY2hTaW1DSSkgPC0gbGlzdChibmFtLCBjb25mKQ0KIyBTY2hTaW1DSQ0KZDE8LVNjaFNpbUNJWzEsXQ0KZDI8LVNjaFNpbUNJWzIsXQ0KZGZfcHZhbF9kcm9wX3AxIDwtIGRhdGEuZnJhbWUoIjEiID0gcmVwKDAsMyksIjIiID0gcmVwKDAsMyksIjMiID0gcmVwKDAsMyksIjQiID0gcmVwKDAsMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXM9YygiSDJTIiwiTGFjdGljIiwiUG9yY2VudGFqZSIpKQ0KY29sbmFtZXMoZGZfcHZhbF9kcm9wX3AxKSA8LSAgICBjKCJCb25mZXJyb25pIiwiQm9uZmVycm9uaSIsIlNjaGVmZsOpIiwiU2NoZWZmw6kiKQ0KZGZfcHZhbF9kcm9wX3AxWzEsXSA8LSBjKGMxLGQxKQ0KZGZfcHZhbF9kcm9wX3AxWzIsXSA8LSBjKGMyLGQyKQ0KZGZfcHZhbF9kcm9wX3AxWzMsXSA8LSBjKCI1JSIsIjk1JSIsIjUlIiwiOTUlIikNCmRmX3B2YWxfZHJvcF9wMQ0KYGBgDQpGaW5hbG1lbnRlIGJ1c2NhbW9zIHVuYSByZXByZXNlbnRhY2nDs24gZGUgbGEgcmVncmVzacOzbiBxdWUgdGVuZW1vcyBlbiAzIGRpbWVuc2lvbmVzIHlhIHF1ZSBlbCBtb2RlbG8gZmluYWwgY29uc3RhIGRlIHVuYSB2YXJpYWJsZSByZXNwdWVzdGEgeSBkb3MgcHJlZGljdG9yYXMgeSB2ZW1vcyBlbCBwbGFubyBkZSByZWdyZXNpw7NuLCBtYXJjYW5kbyBlbiByb2pvIGxhcyBvYnNlcnZhY2lvbmVzIHF1ZSBwZW9yIHNlIGFqdXN0YW4uDQo8IS0tIEFxdWkgdmEgZXNvLCBzaSBsbyBwdWVkZSBvbmVyIG90cm8gbWVqb3IsIHBxIGEgbWkgaGF5IHVuYSBncmFmaWNhIHF1ZSBubyBzZSBtZSBlamVjdXRhIC0tPg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcGxvdF9seSh4PUgyUywgeT1MYWN0aWMsIHo9dGFzdGUsIHR5cGU9InNjYXR0ZXIzZCIsIG1vZGU9Im1hcmtlciIsIGNvbG9yPXRhc3RlKSAlPiUgDQogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0gyUyAoJSknKSwNCiAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnTGFjdGljICglKScpLA0KICAgICAgICAgICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICdUYXN0ZSAoMC0xMDApJykpKQ0KcGxhbmVyZWcgPC0gc2NhdHRlcnBsb3QzZCh4PUgyUywgeT1MYWN0aWMsIHo9dGFzdGUsIHBjaD0xNiwgY2V4LmxhYj0xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdobGlnaHQuM2Q9VFJVRSwgdHlwZT0iaCIsIHhsYWI9J0gyUyAoJSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiPSdMYWN0aWMgKCUpJywgemxhYj0nVGFzdGUgKDAtMTAwKScpDQpwbGFuZXJlZyRwbGFuZTNkKG1vZGVsLnksIGx0eS5ib3g9InNvbGlkIiwgY29sPSdtZWRpdW1ibHVlJykNCmBgYA0KDQoNCg0KIyAgQW5leG8NCg0KYGBge3IgZWNobyBUUlVFLGV2YWw9RkFMU0V9DQoNCg0KaW5zdGFsbC5wYWNrYWdlcygiZmFyYXdheSIpDQppbnN0YWxsLnBhY2thZ2VzKCJsZWFwcyIpDQppbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCmluc3RhbGwucGFja2FnZXMoIlBBU1dSIikNCmluc3RhbGwucGFja2FnZXMoImNhciIpDQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCmluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpDQppbnN0YWxsLnBhY2thZ2VzKCJjb3JycGxvdCIpDQppbnN0YWxsLnBhY2thZ2VzKCJzY2F0dGVycGxvdDNkIikNCmluc3RhbGwucGFja2FnZXMoImxtdGVzdCIpDQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KaW5zdGFsbC5wYWNrYWdlcygibWl4bG0iKQ0KDQoNCmxpYnJhcnkoZmFyYXdheSkNCmxpYnJhcnkobGVhcHMpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KFBBU1dSKQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoc2NhdHRlcnBsb3QzZCkNCmxpYnJhcnkobG10ZXN0KQ0KbGlicmFyeShtaXhsbSkNCg0KDQoNCg0KDQojIDEpIEludHJvZHVjY2lvbg0KDQpkYXRhKGNoZWRkYXIpDQphdHRhY2goY2hlZGRhcikNCg0KIyBWYXJpYWJsZSBSZXNwdWVzdGE6IHRhc3RlDQojIFZhcmlhYmxlcyBQcmVkaWN0b3JhczogQWNldGljLCBIMlMsIExhY3RpYw0KDQoNCiMgRXN0dWRpYW1vcyBlbCB0aXBvIGRlIGxhcyB2YXJpYWJsZXMgcXVlIHZhbiBhIGZvcm1hciBwYXJ0ZSBkZSBsb3MgcG9zaWJsZXMgbW9kZWxvcw0Kc2FwcGx5KGNoZWRkYXIsIGNsYXNzKSAjIHRvZGFzIGxhcyB2YXJpYWJsZXMgc29uIG51bWVyaWNhcw0KaGVhZChjaGVkZGFyKQ0KDQojIENvbXByb2JhbW9zIHF1ZSBubyBoYXkgZW50cmFkYXMgdmFjaWFzDQphbnkoaXMubmEoY2hlZGRhcikpDQoNCiMgRGUgaGFiZXJsYXMgaGFiaWRvLCBwb2RyaWFtb3MgaGFiZXIgdG9tYWRvIGxhcyBzaWd1aWVudGVzIGRlY2lzaW9uZXM6DQojICAtIGVsaW1pbmFyIGxhcyBvYnNlcnZhY2lvbmVzIGNvbiB2YWxvcmVzIE5BDQojICAtIGVsaW1pbmFyIHZhcmlhYmxlcyBzaSBtdWNoYXMgZGUgbGFzIGVudHJhZGFzIHZhY2lhcyBhcGFyZWNlbiBlbiBlbGxhDQojICAtIGVtcGxlYXIgbcOpdG9kb3MgcGFyYSBwcmVkZWNpciBxdWUgdmFsb3JlcyBkZWJlcmlhbiBhcGVyY2VyIGVuIGRpY2hhcyBlbnRyYWRhcw0KDQoNCg0KIyBIaXN0b2dyYW1hcyBkZSB0b2RhcyBsYXMgdmFyaWFibGVzDQppZHMgPC0gbmFtZXMoY2hlZGRhcikNCmxheW91dChtYXRyaXgoMTo0LCBucm93ID0gMSkpDQp5X2xhYl9zdHJpbmcgPC0gIkNhbnRpZGFkIg0KZm9yIChpZCBpbiBpZHMpIHsNCiAgaGlzdChjaGVkZGFyWywgaWRdLCB4bGFiID0gaWQsIHlsYWIgPSB5X2xhYl9zdHJpbmcsIG1haW4gPSBwYXN0ZSgiSGlzdG9ncmFtIG9mICIsIGlkKSkNCiAgeV9sYWJfc3RyaW5nIDwtICIiDQp9DQoNCg0KIyBHcmFmaWNhcyBkZSBsYXMgcmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMuDQpwbG90KGNoZWRkYXIpDQoNCiMgR3JhZmljYXMgZGUgZGlzcGVyc2lvbiBlbnRyZSBsYSB2YXJpYWJsZSByZXNwdWVzdGEgInRhc3RlIiB5IGxhcyB2YXJpYWJsZXMgcHJlZGljdG9yYXMuDQpsYXlvdXQobWF0cml4KDE6MywgbnJvdyA9IDEpKQ0KDQpwbG90KEFjZXRpYywgdGFzdGUsDQogICAgIG1haW4gPSAiUmVsYWNpw7NuIGVudHJlIFRhc3RlIHkgQWNldGljIiwNCiAgICAgeGxhYiA9ICJBY2V0aWMiLCB5bGFiID0gIlRhc3RlIiwNCiAgICAgcGNoID0gMTksIGZyYW1lID0gRkFMU0UpDQoNCg0KcGxvdChIMlMsIHRhc3RlLA0KICAgICBtYWluID0gIlJlbGFjacOzbiBlbnRyZSBUYXN0ZSB5IEgyUyIsDQogICAgIHhsYWIgPSAiSDJTIiwgeWxhYiA9ICJUYXN0ZSIsDQogICAgIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFKQ0KDQoNCnBsb3QoTGFjdGljLCB0YXN0ZSwNCiAgICAgbWFpbiA9ICJSZWxhY2nDs24gZW50cmUgVGFzdGUgeSBMYWN0aWMiLA0KICAgICB4bGFiID0gIkxhY3RpYyIsIHlsYWIgPSAiVGFzdGUiLA0KICAgICBwY2ggPSAxOSwgZnJhbWUgPSBGQUxTRSkNCg0KDQpsYXlvdXQobWF0cml4KDE6MSwgbnJvdyA9IDEpKQ0Kc3VtbWFyeShjaGVkZGFyKQ0KDQoNCg0KDQoNCiMgMikgRXN0dWRpbyB5IGV2YWx1YWNpb24gZGVsIG1vZGVsbyBjb21wbGV0bw0KDQp4IDwtIG1vZGVsLm1hdHJpeCggfiBBY2V0aWMgKyBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyKQ0KYmV0YWhhdCA8LSBzb2x2ZShjcm9zc3Byb2QoeCwgeCksIGNyb3NzcHJvZCh4LCB0YXN0ZSkpDQpiZXRhaGF0IDwtIGMoYmV0YWhhdCkNCmJldGFoYXQNCg0KIyBDb21wcm9iYW1vcyBlbCByZXN1bHRhZG8gY29uIGZ1bmNpb25lcyB5YSBpbXBsZW1lbnRhZGFzDQptb2RlbC5hbGwgPC0gbG0odGFzdGUgfiAuLCBkYXRhID0gY2hlZGRhcikNCnN1bW1hcnkobW9kZWwuYWxsKQ0KbW9kZWwuYWxsJGNvZWZmaWNpZW50cw0KDQphbm92YShtb2RlbC5hbGwpDQoNCg0KDQojIEludGVydmFsb3MgZGUgY29uZmlhbnphIGRlIGxhcyBiZXRhcyBkZWwgbW9kZWxvIGNvbXBsZXRvDQpjb25maW50KG1vZGVsLmFsbCkNCg0KIyBPYnNlcnZhbW9zIHF1ZSAwIGVzdGEgZW4gZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBkZSBiZXRhXzAgeSBiZXRhX0FjZXRpYywgcGxhbnRlYW1vcyBkb3MgdGVzdHMNCiMgICAgY29uIGhpcMOzdGVzaXMgbnVsYSBiZXRhX2kgPSAwIHkgaGlwb3Rlc2lzIGFsdGVybmF0aXZhIGJldGFfaSAhPSAwLg0KDQojIENvbWVuemFtb3MgY29uIGJldGFfQWNldGljIHB1ZXMgZWwgdmFsb3IgZXN0aW1hZG8gZXMgbcOhcyBjZXJjYW5vIGEgMCBxdWUgZWwgZGUgYmV0YV8wDQptb2Rub0FjZXRpYyA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYywgZGF0YT1jaGVkZGFyKQ0KYW5vdmEobW9kbm9BY2V0aWMsbW9kZWwuYWxsKSAjIG5vIHNvbG8gZWwgcC12YWxvciA+IDAuMDUgc2lubyBxdWUgZGUgaGVjaG8gcC12YWxvciB+IDEsIGFjZXB0YW1vcyBsYSBoaXBvdGVzaXMgbnVsYS4NCg0KbW9kbm9JbnRlcmNlcHRvciA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYyArIDAsIGRhdGE9Y2hlZGRhcikgIyBtb2RlbG8gcmVkdWNpZG8gc2luIGludGVyY2VwdG9yDQphbm92YShtb2Rub0ludGVyY2VwdG9yLG1vZGVsLmFsbCkgIyBlbCBwLXZhbG9yIGVzIG1lbm9yIHF1ZSAwLjA1LCBsdWVnbyBubyBlcyBzdWZpY2llbnRlIHBhcmEgcmVjaGF6YXIgbGEgaGlwb3Rlc2lzIG51bGENCg0KDQojIFZlYW1vcyBsb3MgcC12YWxvcmVzIGRlIGxhcyB2YXJpYWJsZXMgcHJlZGljdG9yYXMNCnN1bW1hcnkobW9kZWwuYWxsKSRjb2VmZlssNF0NCiMgT2JzZXJ2YW1zbyBxdWUgZWwgcC12YWxvciBkZSBBY2V0aWMgZXMgZWwgbWFzIGVsZXZhZG8sIGVzdGUgcmVzdWx0YWRvIGp1bnRvIGNvbiBlbCBjb250cmF0ZSBkZSBoaXBvdGVzaXMgcXVlIGhlbW9zIGhlY2hvDQojICBwb2RlbW9zIGRlZHVjaXIgcXVlIGxhIHZhcmlhYmxlIEFjZXRpYyBubyBzZXJhIG11eSByZWxldmFudGUgcGFyYSBlbCBlc3R1ZGlvIGRlIGxvcyBkaXN0aW50b3MgbW9kZWxvcyBxdWUgZXN0dWRpYXJlbW9zLg0KDQoNCiMgQ29ycmVsYWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIHF1ZSBpbnRlcnZpZW5lbiBlbiBlbCBtb2RlbG8gY29tcGxldG8NCmNvcihjaGVkZGFyKQ0KZ2dwYWlycyhjaGVkZGFyKQ0KDQptYXRfY29yIDwtIGNvcihjaGVkZGFyLCBtZXRob2QgPSAicGVhcnNvbiIpDQpjb3JycGxvdChtYXRfY29yLCB0eXBlID0gInVwcGVyIiwgb3JkZXIgPSAiaGNsdXN0IiwgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gNDUpDQoNCg0KIyBQb3IgdWx0aW1vIHZlYW1vcyBzaSBoYXkgb3V0bGllcnMgZW4gZWwgbW9kZWxvIGNvbXBsZXRvDQpNb2RlbC5hbGw8LWZvcnRpZnkobW9kZWwuYWxsKQ0Kb3V0bGllclRlc3QobW9kZWwuYWxsKSAjIG5vIGxvcyBoYXkNCg0KIyBQb3IgZWwgbWV0b2RvIGRlIEJvbmZlcnJvbmkNCmFscGhhIDwtIDAuMDUNCkJDViA8LSBxdCgxLWFscGhhLygyKjMwKSwyNikgIyBlbCB2YWxvciBjcml0aWNvIGRlIEJvbmZlcnJvbmkgdF97MS1hbHBoYS8ybjtuLXAtMX0sIG49MzAscD0zDQpCQ1YNCnN1bShhYnMocnN0dWRlbnQobW9kZWwuYWxsKSk+QkNWKSAjIGVsIG1ldG9kbyBubyBub3MgZGEgbmluZ3VuYSBvYnNlcnZhY2lvbg0KDQpzb3J0KGFicyhyc3RhbmRhcmQobW9kZWwuYWxsKSksZGVjcmVhc2luZyA9IFRSVUUpWzE6M10gIyBlc3RvcyB2YWxvcmVzIGVzdGFuIHJlbGF0aXZhbWVudGUgbGVqYW5vcyBkZSBCQ1YNCg0KDQojIFZlYW1vcyBzaSBwb3IgaW5mbHVlbmNlSW5kZXhQbG90KCkgaGF5IGFsZ3VuYSBvYnNlcnZhY2lvbiBxdWUgcHVlZGEgc2VyIHJlbGV2YW50ZQ0KaW5mbHVlbmNlSW5kZXhQbG90KG1vZGVsLmFsbCkgIyBlbiBsYSB0ZXJjZXJhIGdyYWZpY2Egc2UgdmUgcXVlIGxhIG9ic2VydmFjaW9uIDE1IHRpZW5lIHVuIGNvbXBvcnRhbWllbnRvIGFub3JtYWwNCg0KIyBDb21wcm9iZW1vcyBzaSBsb3Mgc3VwdWVzdG9zIGRlIGxvcyBtb2RlbG9zIGRlIHJlZ3Jlc2lvbiBsaW5lYWwgbWVqb3JhbiBhbCByZXRpcmFyIGVzdGEgb2JzZXJ2YWNpb24NCiMgIGRlIG51ZXN0cm8gZGF0YXNldC4gRGUgc2VyIGFzaSwgYWNlcHRhbW9zIHF1ZSBwdWVkYSBzZXIgdW5hIG9ic2VydmFjaW9uIHF1ZSBwZWp1ZGlxdWUgYSBudWVzdHJvIG1vZGVsby4NCm1vZGVsLmFsbF8xNTwtIGxtKHRhc3RlIH4gLiwgZGF0YSA9IGNoZWRkYXJbLTE1LF0pDQoNCiMgSG9tb2NlZGFzdGljaWRhZA0KbmN2VGVzdChtb2RlbC5hbGwpDQpuY3ZUZXN0KG1vZGVsLmFsbF8xNSkgIyBlbXBlb3JhDQoNCiMgTm9ybWFsaWRhZA0Kc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLmFsbCkpDQpzaGFwaXJvLnRlc3QocmVzaWQobW9kZWwuYWxsXzE1KSkjIG1lam9yYQ0KDQojIEF1dG9jb3JyZWxhY2lvbg0KZHVyYmluV2F0c29uVGVzdChtb2RlbC5hbGwpDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLmFsbF8xNSkjIG1lam9yYQ0KDQojIExpbmVhbGlkYWQNCnJlc2V0dGVzdChtb2RlbC5hbGwsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyKQ0KcmVzZXR0ZXN0KG1vZGVsLmFsbF8xNSwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXIpIyBlbXBlb3JhDQoNCiMgRW4gZWwgY29tcHV0byBnbG9iYWwgbm8gcGFyZWNlIHF1ZSBsb3MgcC12YWxvcmVzIGRlIGVzdG9zIHRlc3RzIGRlbiBhIGVudGVuZGVyIHVuYSBtZWpvcmlhIGdlbmVyYWwgZGVsIG1vZGVsby4NCiMgIFNpIGJpZW4gZXMgY2llcnRvLCB0YW1wb2NvIGxvcyBlbXBlb3JhIHkgZGVwZW5kaWVuZG8gZGVsIGNyaXRlcmlvIGEgc2VndWlyIHBvZHJpYW1vcyBkZWNpZGlyIHNpIGVzIHJlbGV2YW50ZSBvIG5vLg0KIyAgTm9zb3Ryb3MgaGVtb3MgZGVjaWRpZG8gbm8gY29uc2lkZXJhciBsYSBvYnNlcnZhY2lvbiAxNSBjb21vIHRhbC4NCg0KDQoNCg0KDQojIDMpIFNlbGVjY2lvbiBkZWwgbWVqb3IgbW9kZWxvLiBNZXRvZG9zIHBvciBwYXNvcyB5IHBvciBjcml0ZXJpb3MNCg0KIyBTZXBhcmFjaW9uIGRlbCBkYXRhc2V0IGVuIGNvbmp1bnRvcyBkZSBlbnRyZW5hbWllbnRvIHkgdGVzdCAoNzAtMzAlKQ0KDQojIEhlbW9zIGNvbnNpZGVyYWRvIHZhcmlhcyBzZW1pbGxhcyBwYXJhIGFiYXJjYXIgbcOhcyBtb2RlbG9zLiBBZGVtw6FzLCBoZW1vcyBpbnRlbnRhZG8gZXZpdGFyDQojICBlbiBsYSBtZWRpZGEgZGUgbG8gcG9pYmxlIHF1ZSBzZSByZXBpdGFuIG11Y2hvcyBlbGVtZW50b3MgZW4gbG9zIGRpc3RpbnRvcyBjb25qdW50b3MgZGUgdGVzdCBzZWxlY2Npb25hZG9zLg0KDQpzZXQuc2VlZCgxKQ0KdHJhaW4uMSA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIHNpemUgPSBucm93KGNoZWRkYXIpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQ0KdGVzdC4xIDwtICghdHJhaW4uMSkNCnN1bSh0ZXN0LjEpDQptb2RlbC5hbGwxIDwtIGxtKHRhc3RlIH4gLiwgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMSxdKQ0KDQpzZXQuc2VlZCgxMTAwKQ0KdHJhaW4uMiA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIHNpemUgPSBucm93KGNoZWRkYXIpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQ0KdGVzdC4yIDwtICghdHJhaW4uMikNCnN1bSh0ZXN0LjIpDQpzdW0odGVzdC4xPT1UUlVFICYgdGVzdC4yPT1UUlVFKSNzb2xvIDEgcHJlc2VndWltb3MNCm1vZGVsLmFsbDIgPC0gbG0odGFzdGUgfiAuLCBkYXRhID0gY2hlZGRhclt0cmFpbi4yLF0pDQoNCnNldC5zZWVkKDUpDQp0cmFpbi4zIDwtIHNhbXBsZShjKFRSVUUsIEZBTFNFKSwgc2l6ZSA9IG5yb3coY2hlZGRhciksIHJlcGxhY2UgPSBUUlVFLCBwcm9iID0gYygwLjcsIDAuMykpDQp0ZXN0LjMgPC0gKCF0cmFpbi4zKQ0Kc3VtKHRlc3QuMykNCnN1bSh0ZXN0LjE9PVRSVUUgJiB0ZXN0LjM9PVRSVUUpDQpzdW0odGVzdC4yPT1UUlVFICYgdGVzdC4zPT1UUlVFKQ0KbW9kZWwuYWxsMyA8LSBsbSh0YXN0ZSB+IC4sIGRhdGEgPSBjaGVkZGFyW3RyYWluLjMsXSkNCg0KDQoNCiMgaSkgQkFDS1dBUkQgKGFscGhhPTAuMDUpDQoNCmRyb3AxKG1vZGVsLmFsbDEsIHRlc3QgPSAiRiIpDQojIHF1aXRhbW9zIEFjZXRpYyBkZWwgbW9kZWxvIHBvciBzZXIgbGEgZGUgbWF5b3IgcC12YWxvcg0KDQptb2RlbC51cGRhdGVCMSA8LSB1cGRhdGUobW9kZWwuYWxsMSwgLiB+IC4gLSBBY2V0aWMpDQpkcm9wMShtb2RlbC51cGRhdGVCMSwgdGVzdCA9ICJGIikNCiMgcXVpdGFtb3MgSDJTIGRlbCBtb2RlbG8gcG9yIHNlciBsYSBkZSBtYXlvciBwLXZhbG9yDQoNCm1vZGVsLnVwZGF0ZUIyIDwtIHVwZGF0ZShtb2RlbC51cGRhdGVCMSwgLiB+IC4gLSBIMlMpDQpkcm9wMShtb2RlbC51cGRhdGVCMiwgdGVzdCA9ICJGIikNCiMgdGVybWluYSBlbCBwcm9jZXNvIHB1ZXMgZWwgcC12YWxvciBkZSBMYWN0aWMgbm8gbGxlZ2EgYSBhbHBoYQ0KDQptb2RlbC4xIDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0pDQpzdW1tYXJ5KG1vZGVsLjEpDQoNCiMgUGFyYSBldml0YXIgcmVwZXRpciBlc3RlIHByb2Nlc28gdXNhbW9zIGVsIHBhY2thZ2UgbWl4bG0gY29uIGVsIHF1ZSBvYnRlbmVtb3MgbG9zIG1pc21vcyByZXN1bHRhZG9zLg0KbW9kZWwuMSA8LSBtaXhsbTo6YmFja3dhcmQobW9kZWwuYWxsMSwgYWxwaGE9MC4wNSkNCnN1bW1hcnkobW9kZWwuMSkgIyBMQUNUSUMNCg0KbW9kZWwuMiA8LSBtaXhsbTo6YmFja3dhcmQobW9kZWwuYWxsMiwgYWxwaGE9MC4wNSkNCnN1bW1hcnkobW9kZWwuMikgIyBIMlMgKyBMQUNUSUMNCg0KbW9kZWwuMyA8LSBtaXhsbTo6YmFja3dhcmQobW9kZWwuYWxsMywgYWxwaGE9MC4wNSkNCnN1bW1hcnkobW9kZWwuMykgIyBIMlMgKyBMQUNUSUMNCg0KDQoNCiMgaWkpIEZPUldBUkQgKGFscGhhPTAuMDUpDQpTQ09QRSA8LSAofiAuICsgQWNldGljICsgSDJTICsgTGFjdGljKQ0KbW9kZWwuaW5pY2lhbCA8LSBsbSh0YXN0ZSB+IDEsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjEsXSkgIyBzb2xvIGNvbiB0ZXJtaW5vIGluZGVwZW5kaWVudGUNCg0KYWRkMShtb2RlbC5pbmljaWFsLCBzY29wZSA9IFNDT1BFLCB0ZXN0ID0gIkYiKQ0KIyBBw7FhZGltb3MgTGFjdGljIHBvciBzZXIgbGEgdmFyaWFibGUgcHJlZGljdG9yYSBjb24gbWVub3IgcC12YWxvcg0KbW9kZWwudXBkYXRlRjEgPC0gdXBkYXRlKG1vZGVsLmluaWNpYWwsIC4gfiAuICsgTGFjdGljKQ0KDQphZGQxKG1vZGVsLnVwZGF0ZUYxLCBzY29wZSA9IFNDT1BFLCB0ZXN0ID0gIkYiKQ0KIyBObyBhw7FhZGltb3MgbmluZ3VuYSB2YXJpYWJsZSBwdWVzIHRvZG9zIGxvcyBwLXZhbG9yZXMgc3VwZXJhbiBsYSBiYXJyZXJhIGRlIGFscGhhDQoNCm1vZGVsLjFhIDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0pDQpzdW1tYXJ5KG1vZGVsLjFhKQ0KDQoNCiMgQWwgaWd1YWwgcXVlIGVuIEJBQ0tXQVJEIHVzYW1vcyBlbCBwYXF1ZXRlIG1peGxtIHBhcmEgYXV0b21hdGl6YXIgZWwgcHJvY2VzbyBkZSBGT1JXQVJELg0KbW9kZWwuMWEgPC0gbWl4bG06OmZvcndhcmQobW9kZWwuYWxsMSwgYWxwaGE9MC4wNSkNCnN1bW1hcnkobW9kZWwuMWEpICMgTEFDVElDDQoNCm1vZGVsLjJhIDwtIG1peGxtOjpmb3J3YXJkKG1vZGVsLmFsbDIsIGFscGhhPTAuMDUpDQpzdW1tYXJ5KG1vZGVsLjJhKSAjIEgyUyArIExBQ1RJQw0KDQptb2RlbC4zYSA8LSBtaXhsbTo6Zm9yd2FyZChtb2RlbC5hbGwzLCBhbHBoYT0wLjA1KQ0Kc3VtbWFyeShtb2RlbC4zYSkgIyBIMlMgKyBMQUNUSUMNCg0KIyBOw7N0ZXNlIHF1ZSBsb3MgbW9kZWxvcyBvYnRlbmlkb3MgcG9yIEJBQ0tXQVJEIHkgRk9SV0FSRCBjb2luY2lkZW4gcGFyYSBjYWRhIGNvbmp1bnRvIHRyYWluLg0KDQoNCg0KIyBpaWkpIENSSVRFUklPUw0KDQojIFIyIGFqdXN0YWRvDQptb2RlbHMxIDwtIHJlZ3N1YnNldHModGFzdGUgfiAuLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0pDQptb2RlbHMyIDwtIHJlZ3N1YnNldHModGFzdGUgfiAuLCBkYXRhID0gY2hlZGRhclt0cmFpbi4yLF0pDQptb2RlbHMzIDwtIHJlZ3N1YnNldHModGFzdGUgfiAuLCBkYXRhID0gY2hlZGRhclt0cmFpbi4zLF0pDQoNCnN1bW1hcnkobW9kZWxzMSkNCnN1bW1hcnkobW9kZWxzMikNCnN1bW1hcnkobW9kZWxzMykNCg0KTVIyYWRqMSA8LSBzdW1tYXJ5KG1vZGVsczEpJGFkanIyDQpNUjJhZGoyIDwtIHN1bW1hcnkobW9kZWxzMikkYWRqcjINCk1SMmFkajMgPC0gc3VtbWFyeShtb2RlbHMzKSRhZGpyMg0KDQpzdW1tYXJ5KG1vZGVsczEpJHdoaWNoW3doaWNoLm1heChNUjJhZGoxKSwgXQ0Kc3VtbWFyeShtb2RlbHMyKSR3aGljaFt3aGljaC5tYXgoTVIyYWRqMiksIF0NCnN1bW1hcnkobW9kZWxzMykkd2hpY2hbd2hpY2gubWF4KE1SMmFkajMpLCBdDQoNCg0KDQojIENwIGRlIE1hbGxvd3MNCk1DcDEgPC0gc3VtbWFyeShtb2RlbHMxKSRjcA0KTUNwMiA8LSBzdW1tYXJ5KG1vZGVsczIpJGNwDQpNQ3AzIDwtIHN1bW1hcnkobW9kZWxzMykkY3ANCg0KDQpzdW1tYXJ5KG1vZGVsczEpJHdoaWNoW3doaWNoLm1pbihNQ3AxKSwgXQ0Kc3VtbWFyeShtb2RlbHMyKSR3aGljaFt3aGljaC5taW4oTUNwMiksIF0NCnN1bW1hcnkobW9kZWxzMykkd2hpY2hbd2hpY2gubWluKE1DcDMpLCBdDQoNCg0KIyBDcml0ZXJpbyBkZSBJbmZvcm1hY2lvbiBkZSBCYXllcyAoQklDKQ0KTUJJQzEgPC0gc3VtbWFyeShtb2RlbHMxKSRiaWMNCk1CSUMyIDwtIHN1bW1hcnkobW9kZWxzMikkYmljDQpNQklDMyA8LSBzdW1tYXJ5KG1vZGVsczMpJGJpYw0KDQpzdW1tYXJ5KG1vZGVsczEpJHdoaWNoW3doaWNoLm1pbihNQklDMSksIF0NCnN1bW1hcnkobW9kZWxzMikkd2hpY2hbd2hpY2gubWluKE1CSUMyKSwgXQ0Kc3VtbWFyeShtb2RlbHMzKSR3aGljaFt3aGljaC5taW4oTUJJQzMpLCBdDQoNCiMgQ3JpdGVyaW8gZGUgSW5mb3JtYWNpb24gZGUgQWthaWtlIChBSUMpDQpzdGVwQUlDKG1vZGVsLmFsbDEsIHNjb3BlID0gU0NPUEUsIGsgPSAyKQ0Kc3RlcEFJQyhtb2RlbC5hbGwyLCBzY29wZSA9IFNDT1BFLCBrID0gMikNCnN0ZXBBSUMobW9kZWwuYWxsMywgc2NvcGUgPSBTQ09QRSwgayA9IDIpDQoNCg0KIyBQYXJhIGVsIGNvbmp1bnRvIHRyYWluLjEgYXBhcmVjZW4gbW9kZWxvcyBjb24gTGFjdGljIHkgSDJTICsgTGFjdGljIGNvbW8gdmFyaWFibGVzIHByZWRpY3RvcmFzLA0KIyAgbWllbnRyYXMgcXVlIHBhcmEgbG9zIGNvbmp1bnRvcyB0cmFpbi4yIHkgdHJhaW4uMyB1bmljYW1lbnRlIGFwYXJlY2UgZWwgbW9kZWxvIHRhc3RlIH4gSDJTICsgTGFjdGljLg0KbW9kZWwuMWNyaXQgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGE9Y2hlZGRhclt0cmFpbi4xLF0pDQoNCiMgRXN0byBub3MgcHVlZGUgbGxldmFyIGEgcGVuc2FyIHF1ZSBlbCBtb2RlbG8gZmluYWwgdmF5YSBhIHNlciBlbCBxdWUgdXRpbGl6YSBIMlMgeSBMYWN0aWMuDQoNCm1vZGVsLjENCm1vZGVsLjFjcml0DQptb2RlbC4yDQptb2RlbC4zDQoNCmFub3ZhKG1vZGVsLjEsbW9kZWwuYWxsMSkNCmFub3ZhKG1vZGVsLjFjcml0LG1vZGVsLmFsbDEpDQphbm92YShtb2RlbC4yLG1vZGVsLmFsbDIpDQphbm92YShtb2RlbC4zLG1vZGVsLmFsbDMpDQojIERlIGVzdGEgZm9ybWEgdmVtb3MgcXVlIGxvcyBtb2RlbG9zIGNyZWFkb3Mgc29uIG1lam9yZXMgcXVlIGxvcyBjb21wbGV0b3MuDQoNCg0KDQoNCg0KIyA0KSBEaWFnbm9zdGljby4gQ29tcHJvYmFjaW9uZXMgZGUgaGlwb3Rlc2lzLCBvdXRsaWVycyB5IG9ic2VydmFjaW9uZXMgaW5mbHV5ZW50ZXMNCg0KIyBDb21wcm9iYWNpb24gZGUgaGlwb3Rlc2lzIGRlIGxvcyAgbW9kZWxvcw0KDQojIExpbmVhbGlkYWQNCg0KcmVzZXR0ZXN0KG1vZGVsLjEsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjEsXSkNCnJlc2V0dGVzdChtb2RlbC4xY3JpdCwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMSxdKQ0KcmVzZXR0ZXN0KG1vZGVsLjIsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjIsXSkNCnJlc2V0dGVzdChtb2RlbC4zLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4zLF0pDQojIHAtdmFsb3JlcyA+IDAuMDUgbHVlZ28gYWNlcHRhbW9zIGhpcMOzdGVzaXMgZGUgbGluZWFsaWRhZCBlbiB0b2RvcyBsb3MgY2Fzb3MNCg0KcGxvdChjaGVkZGFyJEgyUywgY2hlZGRhciR0YXN0ZSwNCiAgICAgbWFpbiA9ICJSZWxhY2lvbiBlbnRyZSBUYXN0ZSB5IEgyUyIsDQogICAgIHhsYWIgPSAiSDJTIiwgeWxhYiA9ICJUYXN0ZSIsDQogICAgIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFKQ0KcGxvdChjaGVkZGFyJExhY3RpYywgY2hlZGRhciR0YXN0ZSwNCiAgICAgbWFpbiA9ICJSZWxhY2lvbiBlbnRyZSBUYXN0ZSB5IExhY3RpYyIsDQogICAgIHhsYWIgPSAiTGFjdGljIiwgeWxhYiA9ICJUYXN0ZSIsDQogICAgIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFKQ0KDQoNCg0KIyBOb3JtYWxpZGFkIHkgQXV0b2NvcnJlbGFjaW9uDQoNCnNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xKSkgIyBwLXZhbG9yID4gMC4wNSBubyBzZSByZWNoYXphIGxhIGhpcMOzdGVzaXMgbnVsYSwgaS5lLiBsYSBub3JtYWxpZGFkDQpxcW5vcm0ocmVzaWQobW9kZWwuMSkpDQpxcWxpbmUocmVzaWQobW9kZWwuMSkpDQoNCnNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xY3JpdCkpI2JpZW4NCnFxbm9ybShyZXNpZChtb2RlbC4xY3JpdCkpDQpxcWxpbmUocmVzaWQobW9kZWwuMWNyaXQpKQ0KDQpzaGFwaXJvLnRlc3QocmVzaWQobW9kZWwuMikpI2JpZW4NCnFxbm9ybShyZXNpZChtb2RlbC4yKSkNCnFxbGluZShyZXNpZChtb2RlbC4yKSkNCg0Kc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjMpKSNiaWVuDQpxcW5vcm0ocmVzaWQobW9kZWwuMykpDQpxcWxpbmUocmVzaWQobW9kZWwuMykpDQoNCiMgT2JzZXJ2YW1vcyBxdWUgbGFzIGNvbGFzIG5vIHNpZ3VlbiBlbCBtaXNtbyBwYXRyw7NuIHF1ZSBlbCByZXN0byBkZSBkYXRvcywgbG8gcXVlIHBvZHLDrWEgaW5kaWNhciBxdWUNCiMgIGVsIG1vZGVsbyBubyBzaWd1ZSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwuIFNpbiBlbWJhcmdvLCBhbCBubyBhZmVjdGFyIGEgdW4gZ3JhbiBwb3JjZW50YWplIGRlIGxvcyBkYXRvcyB5DQojICB0ZW5pZW5kbyBlbiBjdWVudGEgZWwgcmVzdWx0YWRvIHByZXZpbyBvYnRlbmlkbyBwb3IgZWwgVGVzdCBkZSBTaGFwaXJvLVdpbGsgbm8gcmVjaGF6YW1vcyBsYSBoaXDDs3Rlc2lzIGRlIG5vcm1hbGlkYWQuDQoNCg0KIyBNZWRpYSBkZSBlcnJvcmVzIG51bGENCg0KdC50ZXN0KHJlc2lkKG1vZGVsLjEpLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpDQp0LnRlc3QocmVzaWQobW9kZWwuMWNyaXQpLCBtdSA9IDAsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpDQp0LnRlc3QocmVzaWQobW9kZWwuMiksIG11ID0gMCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikNCnQudGVzdChyZXNpZChtb2RlbC4zKSwgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKQ0KIyBwLXZhbG9yZXMgfiAxID4gMC4wNSBsdWVnbyBhY2VwdGFtb3MgbGEgaGlwb3Rlc2lzIG51bGEgZW4gdG9kb3MgbG9zIGNhc29zDQoNCg0KDQojIEF1dG9jb3JyZWxhY2lvbg0KDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjEpDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjFjcml0KQ0KZHVyYmluV2F0c29uVGVzdChtb2RlbC4yKQ0KZHVyYmluV2F0c29uVGVzdChtb2RlbC4zKQ0KIyBwLXZhbG9yZXMgPiAwLjA1IGx1ZWdvIHJlY2hhemFtb3MgcXVlIGhheWEgYXV0b2NvcnJlbGFjaW9uDQoNCg0KDQojIEhvbW9jZWRhc3RpY2lkYWQNCg0KZm1vZGVsMSA8LSBmb3J0aWZ5KG1vZGVsLjEpDQpmbW9kZWwxY3JpdCA8LSBmb3J0aWZ5KG1vZGVsLjFjcml0KQ0KZm1vZGVsMiA8LSBmb3J0aWZ5KG1vZGVsLjIpDQpmbW9kZWwzIDwtIGZvcnRpZnkobW9kZWwuMykNCg0KWDEgPC0gZm1vZGVsMSQuZml0dGVkDQpZMSA8LSBmbW9kZWwxJC5zdGRyZXNpZA0KDQpYMWNyaXQgPC0gZm1vZGVsMWNyaXQkLmZpdHRlZA0KWTFjcml0IDwtIGZtb2RlbDFjcml0JC5zdGRyZXNpZA0KDQpYMiA8LSBmbW9kZWwyJC5maXR0ZWQNClkyIDwtIGZtb2RlbDIkLnN0ZHJlc2lkDQoNClgzIDwtIGZtb2RlbDMkLmZpdHRlZA0KWTMgPC0gZm1vZGVsMyQuc3RkcmVzaWQNCg0KcGxvdChYMSwgWTEsIHlsYWIgPSAiUmVzaWR1b3MgZXN0YW5kYXJpemFkb3MiLCB4bGFiID0gInZhbG9yZXMgYWp1c3RhZG9zIikNCnBsb3QoWDFjcml0LCBZMWNyaXQsIHlsYWIgPSAiUmVzaWR1b3MgZXN0YW5kYXJpemFkb3MiLCB4bGFiID0gInZhbG9yZXMgYWp1c3RhZG9zIikNCnBsb3QoWDIsIFkyLCB5bGFiID0gIlJlc2lkdW9zIGVzdGFuZGFyaXphZG9zIiwgeGxhYiA9ICJ2YWxvcmVzIGFqdXN0YWRvcyIpI2Nhc2kgY2FzaSBoYXkgcGF0cm9uDQpwbG90KFgzLCBZMywgeWxhYiA9ICJSZXNpZHVvcyBlc3RhbmRhcml6YWRvcyIsIHhsYWIgPSAidmFsb3JlcyBhanVzdGFkb3MiKQ0KIyBMb3MgcmVzaWR1b3Mgc2UgZGlzdHJpYnV5ZW4gZGUgZm9ybWEgaG9tb2fDqW5lYSBhIGxvIGxhcmdvIGRlIHVuYSBiYW5kYSBob3Jpem9udGFsLCBsdWVnbyBzZSB2ZXJpZmljYSBsYSBoaXDDs3Rlc2lzIG51bGENCg0KDQpuY3ZUZXN0KG1vZGVsLjEpDQpuY3ZUZXN0KG1vZGVsLjFjcml0KQ0KbmN2VGVzdChtb2RlbC4yKQ0KbmN2VGVzdChtb2RlbC4zKQ0KIyBwLXZhbG9yZXMgPiAwLjA1LCBsdWVnbyBubyBoYXkgZXZpZGVuY2lhIHBhcmEgcmVjaGF6YXIgcXVlIGxhIHZhcmlhbnphIHNlYSBjb25zdGFudGUNCg0KDQoNCiMgT3V0bGllcnMNCg0KYWxwaGEgPC0gMC4wNQ0KbjEgPC0gbnJvdyhjaGVkZGFyW3RyYWluLjEsXSkNCnAxIDwtIG5yb3coc3VtbWFyeShtb2RlbC4xKSRjb2VmKQ0KDQpuMWNyaXQgPC0gbnJvdyhjaGVkZGFyW3RyYWluLjEsXSkNCnAxY3JpdCA8LSBucm93KHN1bW1hcnkobW9kZWwuMWNyaXQpJGNvZWYpDQoNCm4yIDwtIG5yb3coY2hlZGRhclt0cmFpbi4yLF0pDQpwMiA8LSBucm93KHN1bW1hcnkobW9kZWwuMikkY29lZikNCg0KbjMgPC0gbnJvdyhjaGVkZGFyW3RyYWluLjMsXSkNCnAzIDwtIG5yb3coc3VtbWFyeShtb2RlbC4zKSRjb2VmKQ0KDQoNCiMgRWwgdmFsb3IgY3JpdGljbyBkZSBCb25mZXJyb25pIHRfezEtYWxwaGEvMm47bi1wLTF9DQpCQ1YxIDwtIHF0KDEgLSBhbHBoYSAvICgyICogbjEpLCBuMS1wMS0xKQ0KQkNWMWNyaXQgPC0gcXQoMSAtIGFscGhhIC8gKDIgKiBuMWNyaXQpLCBuMWNyaXQtcDFjcml0LTEpDQpCQ1YyIDwtIHF0KDEgLSBhbHBoYSAvICgyICogbjIpLCBuMi1wMi0xKQ0KQkNWMyA8LSBxdCgxIC0gYWxwaGEgLyAoMiAqIG4zKSwgbjMtcDMtMSkNCg0Kc3VtKGFicyhyc3R1ZGVudChtb2RlbC4xKSkgPiBCQ1YxKQ0Kc3VtKGFicyhyc3R1ZGVudChtb2RlbC4xY3JpdCkpID4gQkNWMWNyaXQpDQpzdW0oYWJzKHJzdHVkZW50KG1vZGVsLjIpKSA+IEJDVjIpDQpzdW0oYWJzKHJzdHVkZW50KG1vZGVsLjMpKSA+IEJDVjMpDQoNCm91dGxpZXJUZXN0KG1vZGVsLjEpI05BPw0Kb3V0bGllclRlc3QobW9kZWwuMWNyaXQpICNOQT8NCm91dGxpZXJUZXN0KG1vZGVsLjIpDQpvdXRsaWVyVGVzdChtb2RlbC4zKQ0KIyBObyBoYXkgb3V0bGllcnMgZW4gbmluZ3VubyBkZSBsb3MgZG9zIG1vZGVsb3MgcGxhbnRlYWRvcw0KDQoNCg0KIyBPYnNlcnZhY2lvbmVzIEluZmx1eWVudGVzDQoNCiMgQ3JpdGVyaW8gMTogdmFsb3JlcyBsZXZlcmFnZSAoaGlpKSBtYXlvcmVzIHF1ZSAycC9uDQoNClgxIDwtIG1vZGVsLm1hdHJpeCh+IEgyUytMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjEsXSkNClgxY3JpdCA8LSBtb2RlbC5tYXRyaXgofiBIMlMrTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0pDQpYMiA8LSBtb2RlbC5tYXRyaXgofiBIMlMrTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4yLF0pDQpYMyA8LSBtb2RlbC5tYXRyaXgofiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjMsXSkNCg0KSDEgPC0gWDEgJSolIHNvbHZlKHQoWDEpICUqJSBYMSkgJSolIHQoWDEpDQpIMWNyaXQgPC0gWDFjcml0ICUqJSBzb2x2ZSh0KFgxY3JpdCkgJSolIFgxY3JpdCkgJSolIHQoWDFjcml0KQ0KSDIgPC0gWDIgJSolIHNvbHZlKHQoWDIpICUqJSBYMikgJSolIHQoWDIpDQpIMyA8LSBYMyAlKiUgc29sdmUodChYMykgJSolIFgzKSAlKiUgdChYMykNCg0KaGlpMSA8LSBkaWFnKEgxKQ0KaGlpMWNyaXQgPC0gZGlhZyhIMWNyaXQpDQpoaWkyIDwtIGRpYWcoSDIpDQpoaWkzIDwtIGRpYWcoSDMpDQoNCmhDVjEgPC0gMiAqIHAxIC8gbjENCmhDVjFjcml0IDwtIDIgKiBwMWNyaXQgLyBuMWNyaXQNCmhDVjIgPC0gMiAqIHAyIC8gbjINCmhDVjMgPC0gMiAqIHAzIC8gbjMNCg0Kc3VtKGhpaTEgPiBoQ1YxKQ0Kd2hpY2goaGlpMT5oQ1YxKSMxICA1IDE2IDIzIDI0IDI2DQoNCnN1bShoaWkxY3JpdCA+IGhDVjFjcml0KQ0Kd2hpY2goaGlpMWNyaXQ+aENWMWNyaXQpDQoNCnN1bShoaWkyID4gaENWMikNCndoaWNoKGhpaTI+aENWMikNCg0Kc3VtKGhpaTMgPiBoQ1YzKQ0KDQoNCiMgQ3JpdGVyaW8gMjogdmFsb3JlcyB8REZGSVRTfCBzb24gbWF5b3JlcyBxdWUgMipzcXJ0KHAvbikNCg0KZGZmaXRzQ1YxIDwtIDIgKiBzcXJ0KHAxIC8gbjEpDQpkZmZpdHNDVjFjcml0IDwtIDIgKiBzcXJ0KHAxY3JpdCAvIG4xY3JpdCkNCmRmZml0c0NWMiA8LSAyICogc3FydChwMiAvIG4yKQ0KZGZmaXRzQ1YzIDwtIDIgKiBzcXJ0KHAzIC8gbjMpDQoNCmRmZml0c21vZGVsMSA8LSBkZmZpdHMobW9kZWwuMSkNCmRmZml0c21vZGVsMWNyaXQgPC0gZGZmaXRzKG1vZGVsLjFjcml0KQ0KZGZmaXRzbW9kZWwyIDwtIGRmZml0cyhtb2RlbC4yKQ0KZGZmaXRzbW9kZWwzIDwtIGRmZml0cyhtb2RlbC4zKQ0KDQpzdW0oZGZmaXRzbW9kZWwxID4gZGZmaXRzQ1YxKQ0Kd2hpY2goZGZmaXRzbW9kZWwxID4gZGZmaXRzQ1YxKSMxIDEyIDI0DQoNCnN1bShkZmZpdHNtb2RlbDFjcml0ID4gZGZmaXRzQ1YxY3JpdCkNCndoaWNoKGRmZml0c21vZGVsMWNyaXQgPiBkZmZpdHNDVjFjcml0KSMxLCAxMg0KDQpzdW0oZGZmaXRzbW9kZWwyID4gZGZmaXRzQ1YyKQ0Kc3VtKGRmZml0c21vZGVsMyA+IGRmZml0c0NWMykNCg0KDQoNCiMgQ3JpdGVyaW8gMzogdmFsb3JlcyB8REZCRVRBU3wgbWF5b3JlcyBxdWUgMi9zcXJ0KG4pDQoNCmRmYmV0YUNWMSA8LSAyIC8gc3FydChuMSkNCmRmYmV0YUNWMWNyaXQgPC0gMiAvIHNxcnQobjFjcml0KQ0KZGZiZXRhQ1YyIDwtIDIgLyBzcXJ0KG4yKQ0KZGZiZXRhQ1YzIDwtIDIgLyBzcXJ0KG4zKQ0KDQpkZmJldGFtb2RlbDEgPC0gZGZiZXRhKG1vZGVsLjEpDQpkZmJldGFtb2RlbDFjcml0IDwtIGRmYmV0YShtb2RlbC4xY3JpdCkNCmRmYmV0YW1vZGVsMiA8LSBkZmJldGEobW9kZWwuMikNCmRmYmV0YW1vZGVsMyA8LSBkZmJldGEobW9kZWwuMykNCg0KDQpzdW0oZGZiZXRhbW9kZWwxWywgMV0gPiBkZmJldGFDVjEpDQpzdW0oZGZiZXRhbW9kZWwxWywgMl0gPiBkZmJldGFDVjEpDQp3aGljaChkZmJldGFtb2RlbDFbLCAxXSA+IGRmYmV0YUNWMSkNCndoaWNoKGRmYmV0YW1vZGVsMVssIDJdID4gZGZiZXRhQ1YxKQ0KDQpzdW0oZGZiZXRhbW9kZWwxY3JpdFssIDFdID4gZGZiZXRhQ1YxY3JpdCkNCnN1bShkZmJldGFtb2RlbDFjcml0WywgMl0gPiBkZmJldGFDVjFjcml0KQ0Kc3VtKGRmYmV0YW1vZGVsMWNyaXRbLCAzXSA+IGRmYmV0YUNWMWNyaXQpDQp3aGljaChkZmJldGFtb2RlbDFjcml0WywgMV0gPiBkZmJldGFDVjFjcml0KQ0Kd2hpY2goZGZiZXRhbW9kZWwxY3JpdFssIDNdID4gZGZiZXRhQ1YxY3JpdCkNCg0Kc3VtKGRmYmV0YW1vZGVsMlssIDFdID4gZGZiZXRhQ1YyKQ0Kc3VtKGRmYmV0YW1vZGVsMlssIDJdID4gZGZiZXRhQ1YyKQ0Kc3VtKGRmYmV0YW1vZGVsMlssIDNdID4gZGZiZXRhQ1YyKQ0Kd2hpY2goZGZiZXRhbW9kZWwyWywgMV0gPiBkZmJldGFDVjIpDQp3aGljaChkZmJldGFtb2RlbDJbLCAzXSA+IGRmYmV0YUNWMikNCg0Kc3VtKGRmYmV0YW1vZGVsM1ssIDFdID4gZGZiZXRhQ1YzKQ0Kc3VtKGRmYmV0YW1vZGVsM1ssIDJdID4gZGZiZXRhQ1YzKQ0Kc3VtKGRmYmV0YW1vZGVsM1ssIDNdID4gZGZiZXRhQ1YzKQ0Kd2hpY2goZGZiZXRhbW9kZWwzWywgMV0gPiBkZmJldGFDVjMpDQp3aGljaChkZmJldGFtb2RlbDNbLCAzXSA+IGRmYmV0YUNWMykNCg0KIyBEYWRvIHF1ZSBudWVzdHJvIGRhdHNldCBlcyBwZXF1ZcOxbywgbm8gdGVuZHJlbXNvIGVuIGN1ZW50YSBlc3RlIG1ldG9kbyBwb3IgZGFyIGRlbWFzaWFkYXMgb2JzZXJ2YWNpb25lcy4NCg0KDQojIEdyYWZpY2EgY29uIGxhcyBkaXN0YW5jaWFzIGRlIENvb2sNCmluZmx1ZW5jZVBsb3QobW9kZWwuMSkNCnBvc19pbmZsdXllbnRlc18xIDwtIGMoMSwxMiwyNCkNCg0KaW5mbHVlbmNlUGxvdChtb2RlbC4xY3JpdCkNCnBvc19pbmZsdXllbnRlc18xY3JpdCA8LSBjKDEsOCwxMiwyMykNCg0KaW5mbHVlbmNlUGxvdChtb2RlbC4yKQ0KcG9zX2luZmx1eWVudGVzXzIgPC0gYygxLDYsNyw4LDE1KQ0KDQppbmZsdWVuY2VQbG90KG1vZGVsLjMpDQpwb3NfaW5mbHV5ZW50ZXNfMyA8LSBjKDEsNywxNSwxOSwyNCkNCg0KDQoNCiMgQ29saW5lYWxpZGFkDQp2aWYobW9kZWwuMSkgIyB0aWVuZSBzZW50aWRvIHB1ZXMgZW4gbW9kZWwuMSBzb2xvIGhheSB1bmEgdmFyaWFibGUgcHJlZGljdG9yYQ0KdmlmKG1vZGVsLjFjcml0KQ0KdmlmKG1vZGVsLjIpDQp2aWYobW9kZWwuMykgIyBjb21vIGxvcyB2YWxvcmVzIGRlIFZJRiBubyBzb24gZ3JhbmRvLCBubyBpbmRpY2FuIGNvbGluZWFsaWRhZCBncmF2ZQ0KDQoNCiMgVmFtb3MgYSB0b21hciBjb21vIHBvc2libGVzIGluZmx1eWVudGVzIGxhcyBxdWUgYXBhcmVjZW4gcG9yIHZhcmlvcyBtZXRvZG9zIGVuIGNhZGEgbW9kZWxvDQoNCiMgRW4gZWwgMTogMSAxMg0KcG9zXzEgPC0gYyhUUlVFLHJlcChGQUxTRSwxMCksVFJVRSxyZXAoRkFMU0UsMTgpKQ0KdHJhaW4uMWluZiA8LSB0cmFpbi4xJiFwb3NfMQ0KbW9kZWwuMWluZiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMWluZixdKQ0KDQpuY3ZUZXN0KG1vZGVsLjEpDQpuY3ZUZXN0KG1vZGVsLjFpbmYpICMgZW1wZW9yYSBwZXJvIHNpZ3VlIGN1bXBsaWVuZG8gbGEgaGlwb3Rlc2lzDQoNCnNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xKSkNCnNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xaW5mKSkgIyBtZWpvcmEgcG9jbw0KDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjEpDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjFpbmYpICMgbWVqb3JhDQoNCnJlc2V0dGVzdChtb2RlbC4xLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4xaW5mLF0pDQpyZXNldHRlc3QobW9kZWwuMWluZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMWluZixdKSAjIG1lam9yYSBiYXN0YW50ZQ0KDQojIFJlZGVmaW5pbW9zIGVsIG1vZGVsbyBlbGltaW5hbmRvIGxhcyBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzIGRlIHBvc18xLg0KdHJhaW4uMWF1eDwtdHJhaW4uMQ0KdHJhaW4uMSA8LSB0cmFpbi4xaW5mDQptb2RlbC4xIDwtIG1vZGVsLjFpbmYNCg0KDQojIEVuIGVsIDFjcml0OiAxIDEyICAyMw0KcG9zXzFjcml0IDwtIGMoVFJVRSxyZXAoRkFMU0UsMTApLFRSVUUscmVwKEZBTFNFLDEwKSxUUlVFLHJlcChGQUxTRSw3KSkNCnRyYWluLjFjcml0aW5mIDwtIHRyYWluLjEmIXBvc18xY3JpdA0KbW9kZWwuMWNyaXRpbmYgPC0gbG0odGFzdGUgfkgyUytMYWN0aWMgLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xY3JpdGluZixdKQ0KDQpuY3ZUZXN0KG1vZGVsLjFjcml0KQ0KbmN2VGVzdChtb2RlbC4xY3JpdGluZikgIyBlbXBlb3JhDQoNCnNoYXBpcm8udGVzdChyZXNpZChtb2RlbC4xY3JpdCkpDQpzaGFwaXJvLnRlc3QocmVzaWQobW9kZWwuMWNyaXRpbmYpKSAjIG1lam9yYQ0KDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjFjcml0KQ0KZHVyYmluV2F0c29uVGVzdChtb2RlbC4xY3JpdGluZikgIyBtZWpvcmEgYmFzdGFudGUNCg0KcmVzZXR0ZXN0KG1vZGVsLjFjcml0LCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4xLF0pDQpyZXNldHRlc3QobW9kZWwuMWNyaXRpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjFjcml0aW5mLF0pICMgZW1wZW9yYSBkZW50cm8gZGUgYWNlcHRhYmxlDQoNCiMgUmVkZWZpbmltb3MgZWwgbW9kZWxvIGVsaW1pbmFuZG8gbGFzIG9ic2VydmFjaW9uZXMgaW5mbHV5ZW50ZXMgZGUgcG9zXzFjcml0Lg0KdHJhaW4uMWNyaXQgPC0gdHJhaW4uMWNyaXRpbmYNCm1vZGVsLjFjcml0IDwtIG1vZGVsLjFjcml0aW5mDQoNCg0KIyBFbiBlbCAyOiA2DQpwb3NfMiA8LSBjKHJlcChGQUxTRSw1KSxUUlVFLHJlcChGQUxTRSwyNCkpDQp0cmFpbi4yaW5mIDwtIHRyYWluLjImIXBvc18yDQptb2RlbC4yaW5mIDwtIGxtKHRhc3RlIH4gSDJTK0xhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMmluZixdKQ0KDQpuY3ZUZXN0KG1vZGVsLjIpDQpuY3ZUZXN0KG1vZGVsLjJpbmYpICMgbWVqb3JhIHBvY28NCg0Kc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjIpKQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLjJpbmYpKSAjIGFwcm94aW1hZGFtZW50ZSBsbyBtaXNtbw0KDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjIpDQpkdXJiaW5XYXRzb25UZXN0KG1vZGVsLjJpbmYpICMgbWVqb3JhDQoNCnJlc2V0dGVzdChtb2RlbC4yLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4yaW5mLF0pDQpyZXNldHRlc3QobW9kZWwuMmluZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uMmluZixdKSAjIGFwcm94aW1hZGFtZW50ZSBsbyBtaXNtbw0KDQojIFJlZGVmaW5pbW9zIGVsIG1vZGVsbyBlbGltaW5hbmRvIGxhcyBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzIGRlIHBvc18yLg0KdHJhaW4uMiA8LSB0cmFpbi4yaW5mDQptb2RlbC4yIDwtIG1vZGVsLjJpbmYNCg0KDQojIEVuIGVsIG1vZGVsbyAzIG5vIGhhY2Vtb3MgY29tcHJvYmFjaW9uZXMgbmFkYSB5YSBxdWUgbm8gc2UgcmVwaXRlbiBvYnNlcnZhY2lvbmVzIHBvciBkaXN0aW50b3MgbWV0b2Rvcy4NCg0KDQoNCg0KDQojIDUpIEVycm9yZXMgZGUgVGVzdC4gQ29tcGFyYWNpb24gZGUgTW9kZWxvcw0KDQojIFZhbW9zIGEgY29uc2lkZXJhciBvdHJhcyBkb3Mgc2VtaWxsYXMgcGFyYSBldmFsdWFyIGxvcyBtb2RlbG9zIHkgZWxlZ2lyIGVsIG1lam9yLg0KIyBMYXMgdG9tYW1vcyBkZSBmb3JtYSBxdWUgbm8gY29pbmNpZGFuIGVuIGxhIG1lZGlkYSBkZSBsbyBwb3NpYmxlIGxvcyB0ZXN0cyBkZSBsYXMgZGlzdGludGFzIHBhcnRpY2lvbmVzLg0KIyBEaXZpZGltb3MgZWwgY29uanVudG8gdG90YWwgcGFyYSBsYXMgZG9zIHNlbWlsbGFzIG51ZXZhcy4NCg0Kc2V0LnNlZWQoKDIyMzQpKQ0KdHJhaW4uNCA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIHNpemUgPSBucm93KGNoZWRkYXIpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQ0KdGVzdC40IDwtICghdHJhaW4uNCkNCnN1bSh0ZXN0LjQpDQpzdW0odGVzdC4xPT1UUlVFICYgdGVzdC40PT1UUlVFKQ0Kc3VtKHRlc3QuMj09VFJVRSAmIHRlc3QuND09VFJVRSkNCnN1bSh0ZXN0LjM9PVRSVUUgJiB0ZXN0LjQ9PVRSVUUpDQoNCg0Kc2V0LnNlZWQoKDEzMSkpDQp0cmFpbi41IDwtIHNhbXBsZShjKFRSVUUsIEZBTFNFKSwgc2l6ZSA9IG5yb3coY2hlZGRhciksIHJlcGxhY2UgPSBUUlVFLCBwcm9iID0gYygwLjcsIDAuMykpDQp0ZXN0LjUgPC0gKCF0cmFpbi41KQ0Kc3VtKHRlc3QuNSkNCnN1bSh0ZXN0LjE9PVRSVUUgJiB0ZXN0LjU9PVRSVUUpDQpzdW0odGVzdC4yPT1UUlVFICYgdGVzdC41PT1UUlVFKQ0Kc3VtKHRlc3QuMz09VFJVRSAmIHRlc3QuNT09VFJVRSkNCnN1bSh0ZXN0LjQ9PVRSVUUgJiB0ZXN0LjU9PVRSVUUpDQoNCnRyYWluLjFoIDwtIHRyYWluLjFjcml0DQp0cmFpbi4yaCA8LSB0cmFpbi4yDQp0cmFpbi4zaCA8LSB0cmFpbi4zDQp0cmFpbi40aCA8LSB0cmFpbi40DQp0cmFpbi41aCA8LSB0cmFpbi41DQoNCiMgUmVjYWxjdWxhbW9zIHRyYWluLjIgcG9ycXVlIGZ1ZSBtb2RpZmljYWRvDQpzZXQuc2VlZCgxMTAwKQ0KdHJhaW4uMiA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIHNpemUgPSBucm93KGNoZWRkYXIpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQ0KDQoNCg0KDQojIFZlYW1zbyBzaSBwb2RlbW9zIGVsaW1pbmFyIHBvc2libGVzIGluZmx1eWVudGVzIGVuIGxvcyBtb2RlbG9zIHJlc3RhbnRlcw0KDQptaDEgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjFoLF0pICMgY29tcHJvYmFkb3Mgc3VwdWVzdG9zDQptaDIgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjJoLF0pICMgY29tcHJvYmFkb3Mgc3VwdWVzdG9zDQptaDMgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjNoLF0pICMgY29tcHJvYmFkb3Mgc3VwdWVzdG9zDQptaDQgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjRoLF0pDQptaDUgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjVoLF0pDQoNCm0xIDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi4xLF0pICMgY29tcHJvYmFkb3Mgc3VwdWVzdG9zDQptMiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uMixdKQ0KbTMgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjMsXSkNCm00IDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi40LF0pDQptNSA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNSxdKQ0KDQoNCiMgQWwgaWd1YWwgcXVlIGhpY2ltb3MgZW4gNCBjb21wcm9iYW1vcyBzaSByZXRpcmFuZG8gb3V0bGllcnMgeSBvYnNlcnZhY2lvbmVzIGluZmx1eWVudGVzIG1lam9yYW4gbGFzIGhpcG90ZXNpcy4NCiMgIFVuaWNhbWVudGUgY29uc2lkZXJhcmVtb3Mgb2JzZXJ2YWNpb25lcyBvYnRlbmlkYXMgdGFudG8gcG9yIG91dGxpZXJUZXN0KCkgY29tbyBwb3IgaW5mbHVlbmNlUGxvdCgpLg0KDQojIG1oNA0Kb3V0bGllclRlc3QobWg0KQ0KaW5mbHVlbmNlUGxvdChtaDQpICMgNiwxMiwxNSwyNA0KcG9zNGggPC0gYyhyZXAoRkFMU0UsNSksVFJVRSxyZXAoRkFMU0UsNSksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsOCksVFJVRSxyZXAoRkFMU0UsNikpDQoNCnRyYWluLjRpbmYgPC0gdHJhaW4uNGgmIXBvczRoDQptaDRpbmYgPC0gbG0odGFzdGUgfiBIMlMrTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi40aW5mLF0pDQoNCm5jdlRlc3QobWg0KQ0KbmN2VGVzdChtaDRpbmYpICMgbWVqb3JhIE1VQ0hPDQoNCnNoYXBpcm8udGVzdChyZXNpZChtaDQpKQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG1oNGluZikpICMgbWVqb3JhDQoNCmR1cmJpbldhdHNvblRlc3QobWg0KQ0KZHVyYmluV2F0c29uVGVzdChtaDRpbmYpICMgbWVqb3JhDQoNCnJlc2V0dGVzdChtaDQsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjRpbmYsXSkNCnJlc2V0dGVzdChtaDRpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjRpbmYsXSkgIyBlbXBlb3JhIHBlcm8gZXMgYWNlcHRhYmxlDQoNCiMgUmVkZWZpbmltb3MgZWxpbWluYW5kbyBwb3M0aCBwb3Igc2VyIHRhbnRhIGxhIG1lam9yYSBlbiBob21vY2VkYXN0aWNpZGFkIHF1ZSBjb21wZW5zYSBsYSBsaW5lYWxpZGFkDQp0cmFpbi40aCA8LSB0cmFpbi40aW5mDQptaDQgPC0gbWg0aW5mDQoNCg0KIyBtaDUNCm91dGxpZXJUZXN0KG1oNSkNCmluZmx1ZW5jZVBsb3QobWg1KSAjIDYsNyw4LDEyLDE1DQpwb3M1aCA8LSBjKHJlcChGQUxTRSw1KSxUUlVFLFRSVUUsVFJVRSxyZXAoRkFMU0UsMyksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsMTUpKQ0KDQp0cmFpbi41aW5mIDwtIHRyYWluLjVoJiFwb3M1aA0KbWg1aW5mIDwtIGxtKHRhc3RlIH4gSDJTK0xhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uNWluZixdKQ0KDQpuY3ZUZXN0KG1oNSkNCm5jdlRlc3QobWg1aW5mKSAjIG1lam9yYQ0KDQpzaGFwaXJvLnRlc3QocmVzaWQobWg1KSkNCnNoYXBpcm8udGVzdChyZXNpZChtaDVpbmYpKSAjIGVtcGVvcmENCg0KZHVyYmluV2F0c29uVGVzdChtaDUpDQpkdXJiaW5XYXRzb25UZXN0KG1oNWluZikgIyBhIHZlY2VzIG5vIHNlIGN1bXBsZSBsYSBoaXBvdGVzaXMgbnVsYSBkZSBubyBhdXRvY29ycmVsYWNpb24NCg0KcmVzZXR0ZXN0KG1oNSwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNWluZixdKQ0KcmVzZXR0ZXN0KG1oNWluZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNWluZixdKSAjIGVtcGVvcmENCg0KIyBEZWNpZGltb3Mgbm8gYWN0dWFsaXphciBlbCBtb2RlbG8gcHVlcyBubyBzaWVtcHJlIHNlIHJlY2hhemEgbGEgY29ycmVsYWNpb24geSBlbXBlb3JhbiBvdHJvcyBwLXZhbG9yZXMuDQoNCg0KIyBtMg0Kb3V0bGllclRlc3QobTIpDQppbmZsdWVuY2VQbG90KG0yKSAjIDEsMTIsMTUsMTgsMjQNCnBvczIgPC0gYyhUUlVFLHJlcChGQUxTRSwxMCksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsNSksVFJVRSxyZXAoRkFMU0UsNikpDQoNCnRyYWluLjJpbmYgPC0gdHJhaW4uMiYhcG9zMg0KbTJpbmYgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjJpbmYsXSkNCg0KbmN2VGVzdChtMikNCm5jdlRlc3QobTJpbmYpICMgZW1wZW9yYSBsaWdlcmFtZW50ZQ0KDQpzaGFwaXJvLnRlc3QocmVzaWQobTIpKQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG0yaW5mKSkgIyBlbXBlb3JhIGxpZ2VyYW1lbnRlDQoNCmR1cmJpbldhdHNvblRlc3QobTIpDQpkdXJiaW5XYXRzb25UZXN0KG0yaW5mKSAjIGVtcGVvcmEgYmFzdGFudGUNCg0KcmVzZXR0ZXN0KG0yLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi4yaW5mLF0pDQpyZXNldHRlc3QobTJpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjJpbmYsXSkgIyBtZWpvcmENCg0KIyBEZWNpY2ltb3Mgbm8gcmVkZWZpbmlybG8sIHlhIHF1ZSBlbXBlb3JhIGVuIG11Y2hhcyB5IG1lam9yYSBiYXN0YW50ZSBlbiB1bmENCg0KDQojIG0zDQpvdXRsaWVyVGVzdChtMykNCmluZmx1ZW5jZVBsb3QobTMpICMgMSwxNSwxOSwyNA0KcG9zMyA8LSBjKFRSVUUscmVwKEZBTFNFLDEzKSxUUlVFLHJlcChGQUxTRSwzKSxUUlVFLHJlcChGQUxTRSw0KSxUUlVFLHJlcChGQUxTRSw2KSkNCg0KdHJhaW4uM2luZiA8LSB0cmFpbi4zJiFwb3MzDQptM2luZiA8LSBsbSh0YXN0ZSB+IExhY3RpYywgZGF0YSA9IGNoZWRkYXJbdHJhaW4uM2luZixdKQ0KDQpuY3ZUZXN0KG0zKQ0KbmN2VGVzdChtM2luZikgIyBtZWpvcmEgcG9jbw0KDQpzaGFwaXJvLnRlc3QocmVzaWQobTMpKQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG0zaW5mKSkgIyBtZWpvcmENCg0KZHVyYmluV2F0c29uVGVzdChtMykNCmR1cmJpbldhdHNvblRlc3QobTNpbmYpICMgZW1wZW9yYQ0KDQpyZXNldHRlc3QobTMsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjNpbmYsXSkNCnJlc2V0dGVzdChtM2luZiwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uM2luZixdKSAjIGVtcGVvcmEgY2FzaSBsbyBwaWVyZGUNCg0KIyBEZWNpZGltb3Mgbm8gcmVkZWZpbmlybG8gcG9yIGVzdGFyIGFsIGJvcmRlIGVuIHVuIGNyaXRlcmlvIHkgbm8gbWVqb3JhciBtdWNobyBlbiBvdHJvcw0KDQoNCiMgbTQNCm91dGxpZXJUZXN0KG00KQ0KaW5mbHVlbmNlUGxvdChtNCkgIyA2LDEyLDE1LDIwLDI0DQpwb3M0IDwtIGMocmVwKEZBTFNFLDUpLFRSVUUscmVwKEZBTFNFLDUpLFRSVUUscmVwKEZBTFNFLDIpLFRSVUUscmVwKEZBTFNFLDQpLFRSVUUscmVwKEZBTFNFLDMpLFRSVUUscmVwKEZBTFNFLDYpKQ0KDQp0cmFpbi40aW5mIDwtIHRyYWluLjQmIXBvczQNCm00aW5mIDwtIGxtKHRhc3RlIH4gTGFjdGljLCBkYXRhID0gY2hlZGRhclt0cmFpbi40aW5mLF0pDQoNCm5jdlRlc3QobTQpDQpuY3ZUZXN0KG00aW5mKSAjIGVtcGVvcmEgYmFzdGFudGUNCg0Kc2hhcGlyby50ZXN0KHJlc2lkKG00KSkNCnNoYXBpcm8udGVzdChyZXNpZChtNGluZikpICMgZW1wZW9yYQ0KDQpkdXJiaW5XYXRzb25UZXN0KG00KQ0KZHVyYmluV2F0c29uVGVzdChtNGluZikjIGVtcGVvcmEgYmFzdGFudGUNCg0KcmVzZXR0ZXN0KG00LCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi40aW5mLF0pDQpyZXNldHRlc3QobTRpbmYsIHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyW3RyYWluLjRpbmYsXSkgIyBtZWpvcmEgYWxnbw0KDQojIERlY2lkaW1vcyBubyBjYW1iaWFybG8gcG9ycXVlIGVtcGVvcmEgZW4gY2FzaSB0b2RvLCB5IGRlIHBvciBzaSB0ZW5pYSBidWVub3MgcC12YWx1ZXMNCg0KDQojIG01DQpvdXRsaWVyVGVzdChtNSkNCmluZmx1ZW5jZVBsb3QobTUpICMgMSw4LDEyLDE1LDE4LDI0DQpwb3M1IDwtIGMoVFJVRSxyZXAoRkFMU0UsNiksVFJVRSxyZXAoRkFMU0UsMyksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsMiksVFJVRSxyZXAoRkFMU0UsNSksVFJVRSxyZXAoRkFMU0UsNikpDQoNCnRyYWluLjVpbmYgPC0gdHJhaW4uNSYhcG9zNQ0KbTVpbmYgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW3RyYWluLjVpbmYsXSkNCg0KbmN2VGVzdChtNSkNCm5jdlRlc3QobTVpbmYpICMgZW1wZW9yYSBiYXN0YW50ZQ0KDQpzaGFwaXJvLnRlc3QocmVzaWQobTUpKQ0Kc2hhcGlyby50ZXN0KHJlc2lkKG01aW5mKSkgIyBtZWpvcmENCg0KZHVyYmluV2F0c29uVGVzdChtNSkNCmR1cmJpbldhdHNvblRlc3QobTVpbmYpICMgbm8gc2UgdmVyaWZpY2EgbGEgaGlwb3Rlc2lzIG51bGEgZGUgbm8gYXV0b2NvcnJlbGFjaW9uDQoNCnJlc2V0dGVzdChtNSwgcG93ZXI9MjozLCB0eXBlPSJyZWdyZXNzb3IiLCBkYXRhPWNoZWRkYXJbdHJhaW4uNWluZixdKQ0KcmVzZXR0ZXN0KG01aW5mLCBwb3dlcj0yOjMsIHR5cGU9InJlZ3Jlc3NvciIsIGRhdGE9Y2hlZGRhclt0cmFpbi41aW5mLF0pICMgZW1wZW9yYQ0KDQojIERlY2lkaW1vcyBubyBjYW1iaWFybG8gcG9yIHBlcmRlcnNlIGxhIGNvcnJlbGFjacOzbg0KDQojIE5vdGVzZSBxdWUgZW4gbG9zIG9yaWdpbmFsZXMgc2llbXByZSBzZSBjdW1wbGlhbiBsYXMgaGlwb3Rlc2lzLCBhdW5xdWUgbm8gZXJhIG5lY2VzYXJpbyBwYXJhIGVsIHByb2Nlc28NCg0KDQoNCg0KbGlzdGFfdGVzdCA8LSBsaXN0KHRlc3QuMSx0ZXN0LjIsdGVzdC4zLHRlc3QuNCx0ZXN0LjUpDQpsaXN0YV90cmFpbmggPC0gbGlzdCh0cmFpbi4xaCx0cmFpbi4yaCx0cmFpbi4zaCx0cmFpbi40aCx0cmFpbi41aCkNCmxpc3RhX3RyYWluIDwtIGxpc3QodHJhaW4uMSx0cmFpbi4yLHRyYWluLjMsdHJhaW4uNCx0cmFpbi41KQ0KDQoNCm1vZGVsb3NfaGlwIDwtIGMoIlMxIHRhc3RlIH4gSDJzICsgTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlMxIHRhc3RlIH4gTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlMyIHRhc3RlIH4gSDJzICsgTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlMyIHRhc3RlIH4gTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlMzIHRhc3RlIH4gSDJzICsgTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlMzIHRhc3RlIH4gTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlM0IHRhc3RlIH4gSDJzICsgTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlM0IHRhc3RlIH4gTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlM1IHRhc3RlIH4gSDJzICsgTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIlM1IHRhc3RlIH4gTGFjdGljIiwNCiAgICAgICAgICAgICAgICAgIk5pdmVsIGRlIHNpZ25pZmljYWNpb24iKQ0KDQpoaXBfUkwgPC0gYygiRGlzdHJpYnVjacOzbl9ub3JtYWwiLA0KICAgICAgICAgICAgIk1lZGlhXzAiLA0KICAgICAgICAgICAgIlZhcmlhbnphX25vX2NvbnN0YW50ZSIsDQogICAgICAgICAgICAiTm9fQXV0b2NvcnJlbGFjacOzbiIpDQpwbGFjZWhvbGRlciA8LSB2ZWN0b3IobW9kZSA9ICJsb2dpY2FsIixsZW5ndGggPSAxMSkNCmRmX2hpcFJMIDwtIGRhdGEuZnJhbWUoIjAiID0gcGxhY2Vob2xkZXIsDQogICAgICAgICAgICAgICAgICAgICAgICIxIiA9IHBsYWNlaG9sZGVyLA0KICAgICAgICAgICAgICAgICAgICAgICAiMiIgPSBwbGFjZWhvbGRlciwNCiAgICAgICAgICAgICAgICAgICAgICAgIjMiID0gcGxhY2Vob2xkZXIsDQogICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IG1vZGVsb3NfaGlwKQ0KDQpjb2xuYW1lcyhkZl9oaXBSTCkgPC0gaGlwX1JMDQoNCnIgPC0gMQ0KZm9yIChkdHJhaW4gaW4gbGlzdGFfdHJhaW5oKXsNCiAgbW9kZWwuSEwubG0gPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsDQogICAgICAgICAgICAgICAgICAgIGRhdGEgPSBjaGVkZGFyW2R0cmFpbixdKQ0KICByZXNpZHVvcyA8LSByZXNpZChtb2RlbC5ITC5sbSkNCiAgbmV3X3JvdyA8LSBjKCkNCg0KICBzaGFwIDwtIHJvdW5kKHNoYXBpcm8udGVzdChyZXNpZHVvcykkcC52YWx1ZSw0KQ0KICB0IDwtIHQudGVzdChyZXNpZHVvcywgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSRwLnZhbHVlDQogIHYgPC0gcm91bmQobmN2VGVzdChtb2RlbC5ITC5sbSkkcCw0KQ0KICBkdyA8LSByb3VuZChkdXJiaW5XYXRzb25UZXN0KG1vZGVsLkhMLmxtKSRwLDQpDQoNCiAgbmV3X3JvdyA9IGMoc2hhcCx0LHYsZHcpDQogIGRmX2hpcFJMW3IsXSA8LSBuZXdfcm93DQogIHIgPSByICsgMg0KfQ0KDQoNCnIgPC0gMg0KZm9yIChkdHJhaW4gaW4gbGlzdGFfdHJhaW4pew0KICBtb2RlbC5MLmxtIDwtIGxtKHRhc3RlIH5MYWN0aWMsDQogICAgICAgICAgICAgICAgICAgZGF0YSA9IGNoZWRkYXJbZHRyYWluLF0pDQogIHJlc2lkdW9zIDwtIHJlc2lkKG1vZGVsLkwubG0pDQogIG5ld19yb3cgPC0gYygpDQoNCiAgc2hhcCA8LSByb3VuZChzaGFwaXJvLnRlc3QocmVzaWR1b3MpJHAudmFsdWUsNCkNCiAgdCA8LSB0LnRlc3QocmVzaWR1b3MsIG11ID0gMCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikkcC52YWx1ZQ0KICB2IDwtIHJvdW5kKG5jdlRlc3QobW9kZWwuTC5sbSkkcCw0KQ0KICBkdyA8LSByb3VuZChkdXJiaW5XYXRzb25UZXN0KG1vZGVsLkwubG0pJHAsNCkNCg0KICBuZXdfcm93ID0gYyhzaGFwLHQsdixkdykNCiAgZGZfaGlwUkxbcixdIDwtIG5ld19yb3cNCiAgciA9IHIgKyAyDQp9DQpkZl9oaXBSTFsxMSxdIDwtIGMocmVwKDAuMDUsNCkpDQpkZl9oaXBSTCAjIFRvZG9zIGxvcyBtb2RlbG9zIGN1bXBsZW4gbGFzIGhpcMOzdGVzaXMNCg0KDQoNCmVycjEgPC0gMA0KZm9yIChpIGluIDUpew0KICBkdHJhaW4gPC0gbGlzdGFfdHJhaW5oW1tpXV0NCiAgZHRlc3QgPC0gbGlzdGFfdGVzdFtbaV1dDQogIGRtb2QgPC0gbG0odGFzdGUgfiBIMlMgKyBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW2R0cmFpbixdKQ0KICBZIDwtIGNoZWRkYXJbZHRlc3QsXSR0YXN0ZQ0KICBZaGF0IDwtIHByZWRpY3Qob2JqID0gZG1vZCwgbmV3ZGF0YSA9IGNoZWRkYXJbZHRlc3QsXSkNCiAgZXJyMSA8LSBlcnIxICsgbWVhbigoWSAtIFloYXQpXjIpDQp9DQplcnIxIDwtIGVycjEvNQ0KZXJyMSAjIEgyUyArIExBQ1RJQyB0aWVuZSBlcnJvciBtZWRpbyAxMS42Mw0KDQoNCmVycjI8LTANCmZvciAoaSBpbiA1KXsNCiAgZHRyYWluIDwtIGxpc3RhX3RyYWluW1tpXV0NCiAgZHRlc3QgPC0gbGlzdGFfdGVzdFtbaV1dDQogIGRtb2QgPC0gbG0odGFzdGUgfiBMYWN0aWMsIGRhdGEgPSBjaGVkZGFyW2R0cmFpbixdKQ0KICBZIDwtIGNoZWRkYXJbZHRlc3QsXSR0YXN0ZQ0KICBZaGF0IDwtIHByZWRpY3Qob2JqID0gZG1vZCwgbmV3ZGF0YSA9IGNoZWRkYXJbZHRlc3QsXSkNCiAgZXJyMiA8LSBlcnIyICsgbWVhbigoWSAtIFloYXQpXjIpDQp9DQplcnIyIDwtIGVycjIvNQ0KZXJyMiAjIExBQ1RJQyB0aWVuZSBlcnJvciBtZWRpbyAxOS40DQoNCmVycjEgPCBlcnIyICMgQ29uY2x1aW1vcyBxdWUgZWwgbW9kZWxvIHRhc3RlIH4gSDJTICsgTGFjdGljIGVzIG1lam9yIHF1ZSB0YXN0ZSB+IExhY3RpYy4NCg0KDQoNCg0KDQojIDYpIENvbmNsdXNpb24NCg0KbW9kZWwueSA8LSBsbSh0YXN0ZSB+IEgyUyArIExhY3RpYyxkYXRhPWNoZWRkYXIpICMgdG9tYW1vcyBlbCBtZWpvciBtb2RlbG8gZGUgbG9zIG9idGVuaWRvcyBlbiA0DQpzdW1tYXJ5KG1vZGVsLnkpDQpwbG90KG1vZGVsLnkpDQoNCiMgVmVhbW9zIGxvcyBwb3NpYmxlcyBvdXRsaWVycw0Kb3V0bGllclRlc3QobW9kZWwueSkNCmluZmx1ZW5jZVBsb3QobW9kZWwueSkNCg0KDQojIEVzdHVkaW8gZGUgaGlww7N0ZXNpcyBzdXB1ZXN0YXMNCg0Kc2hhcGlyby50ZXN0KHJlc2lkKG1vZGVsLnkpKSAjIG5vcm1hbGlkYWQgZGUgcmVzaWR1b3MNCnQudGVzdChyZXNpZChtb2RlbC55KSwgbXUgPSAwLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKSAjIG1lZGlhIGNlcm8gZGUgbG9zIHJlc2lkdW9zDQpuY3ZUZXN0KG1vZGVsLnkpICMgdmFyaWFuemEgY29uc3RhbnRlIGRlIGxvcyByZXNpZHVvcw0KZHVyYmluV2F0c29uVGVzdChtb2RlbC55KSAjIG5vIGF1dG9jb3JyZWxhY2lvbg0KcmVzZXR0ZXN0KG1vZGVsLnkgLHBvd2VyPTI6MywgdHlwZT0icmVncmVzc29yIiwgZGF0YT1jaGVkZGFyKSAjIGxpbmVhbGlkYWQNCg0KIyBFZmVjdGl2YW1lbnRlLCBjdW1wbGUgdG9kYXMgbGFzIGhpcMOzdGVzaXMNCg0KDQpzdW1tYXJ5KG1vZGVsLnkpICMgZW4gZWwgc3VtbWFyeSBvYnNlcnZhbW9zIGxvcyB2YWxvcmVzIGRlIGJldGFoYXQsIHN1cyBwLXZhbG9yZXMgeSBzaWdtYQ0KDQpjb2VmZiA8LSBzdW1tYXJ5KG1vZGVsLnkpJGNvZWZmWywxXQ0KY29lZmYNCg0KIyBDYWxjdWxvIGRlIGludGVydmFsbyBkZSBjb25maWFuemEgZGUgYmV0YTEoSDJTKSB5IGJldGEyKExhY3RpYykNCg0KIyBNZXRvZG8gQm9uZmVycm9uaQ0KYWxwaGEgPC0gMC4xMA0Kc3VtbWFyeShtb2RlbC55KSRjb2VmDQpiIDwtIHN1bW1hcnkobW9kZWwueSkkY29lZlsyOjMsIDFdDQpzLmIgPC0gc3VtbWFyeShtb2RlbC55KSRjb2VmWzI6MywgMl0NCmcgPC0gMw0KbiA8LSBucm93KGNoZWRkYXIpDQpwIDwtIG5jb2woc3VtbWFyeShtb2RlbC55KSRjb2VmKQ0KdF90ZW8gPC0gcXQoMSAtIGFscGhhIC8gKDIgKiBnKSwgbiAtIHApDQpCb21TaW1DSSA8LSBtYXRyaXgoYyhiIC0gdF90ZW8gKiBzLmIsIGIgKyB0X3RlbyAqIHMuYiksIG5jb2wgPSAyKQ0KY29uZiA8LSBjKCI1JSIsICI5NSUiKQ0KYm5hbSA8LSBjKCJIMlMiLCAiTGFjdGljIikNCmRpbW5hbWVzKEJvbVNpbUNJKSA8LSBsaXN0KGJuYW0sIGNvbmYpDQpCb21TaW1DSQ0KDQojIEludGVydmFsbyBkZSBjb25maWFuemEgc2ltdWx0YW5lbyBwb3IgZWwgbWV0b2RvIGRlIFNjaGVmZmUNClEgPC0gcCAtIDENCmZfdGVvIDwtIHFmKDAuOSwgUSwgbiAtIHApIzAuOSBubyBzZXJpYSAwLjk1Pw0KU2NoU2ltQ0kgPC0gbWF0cml4KGMoYiAtIHNxcnQoUSAqIGZfdGVvKSAqIHMuYiwgYiArIHNxcnQoUSAqIGZfdGVvKSAqIHMuYiksIG5jb2wgPSAyKQ0KY29uZiA8LSBjKCI1JSIsICI5NSUiKQ0KYm5hbSA8LSBjKCJIMlMiLCAiTGFjdGljIikNCmRpbW5hbWVzKFNjaFNpbUNJKSA8LSBsaXN0KGJuYW0sIGNvbmYpDQpTY2hTaW1DSQ0KDQoNCiMgTGEgZWN1YWNpw7NuIGRlIG51ZXN0cm8gbW9kZWxvIGZpbmFsIGVzIHkgPSAoLTI3LjYpICsgMy45NSp4X0ggKyAxOS45KnhfTCwNCiMgICAgZG9uZGUgeF9IIHkgeF9MIGRlbm90YW4gbG9zIHZhbG9yZXMgb2JzZXJ2YWRvcyBkZSBIMlMgeSBMYWN0aWMuDQoNCg0KcnNlIDwtIHNxcnQoZGV2aWFuY2UobW9kZWwueSkvZGYucmVzaWR1YWwobW9kZWwueSkpDQpyc2UgICMgdmFyaWFuemEgZGUgbG9zIHJlc2lkdW9zDQoNCnB2YWwgPC0gc3VtbWFyeShtb2RlbC55KSRjb2VmZlssNF0NCnB2YWwgICMgdmVjdG9yIGNvbiBsb3MgcC12YWxvcmVzDQoNCg0KIyBDYWxjdWxvIGRlIHN1IFJeMg0KYW5vdmEobW9kZWwueSkNClNTRSA8LSBhbm92YShtb2RlbC55KVszLDJdDQpTU1QgPC0gYW5vdmEobW9kZWwueSlbMSwyXSthbm92YShtb2RlbC55KVsyLDJdK2Fub3ZhKG1vZGVsLnkpWzMsMl0NCnJzcXIgPC0gMSAtIFNTRS9TU1QNCnJzcXINCnN1bW1hcnkobW9kZWwueSkkci5zcXVhcmVkIyBlcyBsYSBtaXNtYQ0KDQojIENhbGN1bG8gZGUgc3UgUl4yIGFqdXN0YWRhDQpNU0UgPC0gU1NFL2Fub3ZhKG1vZGVsLnkpWzMsMV0NCk1TVCA8LSBTU1QvKGFub3ZhKG1vZGVsLnkpWzEsMV0rYW5vdmEobW9kZWwueSlbMiwxXSthbm92YShtb2RlbC55KVszLDFdKQ0KUmFkaiA8LTEtTVNFL01TVA0KUmFkaiAgIyBzZSBjb21wcnVlYmEgZW4gbGEgdGFibGEgc3VtbWFyeSBxdWUgZWwgdmFsb3IgZXMgY29ycmVjdG8NCg0KDQojIE9ic2VydmFtb3MgY29tbyBzZSBkaXN0cmlidXllIGxhIHZhcmlhYmxlIHRhc3RlIGVuIGZ1bmNpw7NuIGRlIEgyUyB5IExhY3RpYw0KcGxvdF9seSh4PUgyUywgeT1MYWN0aWMsIHo9dGFzdGUsIHR5cGU9InNjYXR0ZXIzZCIsIG1vZGU9Im1hcmtlciIsIGNvbG9yPXRhc3RlKSAlPiUNCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnSDJTICglKScpLA0KICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdMYWN0aWMgKCUpJyksDQogICAgICAgICAgICAgICAgICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gJ1Rhc3RlICgwLTEwMCknKSkpDQoNCg0KIyBWZW1vcyBlbCBwbGFubyBkZSByZWdyZXNpb24gZGVsIG1vZGVsbyBwcm9wdWVzdG8uDQojIEVuIHJvam8gc2UgbWFyY2FuIGxhcyBvYnNlcnZhY2lvbmVzIHF1ZSBwZW9yIHNlIGFqdXN0YW4gYWwgbW9kZWxvLg0KcGxhbmVyZWcgPC0gc2NhdHRlcnBsb3QzZCh4PUgyUywgeT1MYWN0aWMsIHo9dGFzdGUsIHBjaD0xNiwgY2V4LmxhYj0xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdobGlnaHQuM2Q9VFJVRSwgdHlwZT0iaCIsIHhsYWI9J0gyUyAoJSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiPSdMYWN0aWMgKCUpJywgemxhYj0nVGFzdGUgKDAtMTAwKScpDQpwbGFuZXJlZyRwbGFuZTNkKG1vZGVsLnksIGx0eS5ib3g9InNvbGlkIiwgY29sPSdtZWRpdW1ibHVlJykNCmBgYA==